Intl.Collator API
Zeichenketten sprachübergreifend korrekt sortieren und vergleichen
Einführung
Das Sortieren von Strings in JavaScript scheint unkompliziert, bis man auf internationalen Text stößt. Der standardmäßige String-Vergleich verwendet Unicode-Codepoint-Werte, was für viele Sprachen zu falschen Ergebnissen führt. Die Intl.Collator-API bietet einen lokalisierungsorientierten String-Vergleich, der kulturelle Sortierregeln berücksichtigt und Sonderzeichen korrekt behandelt.
Warum die Standardsortierung versagt
Betrachten wir die Sortierung einer Liste deutscher Namen:
const names = ["Zoe", "Ava", "Ärzte", "Änder"];
console.log(names.sort());
// ["Ava", "Zoe", "Änder", "Ärzte"]
Dieses Ergebnis ist für deutschsprachige Benutzer falsch. Im Deutschen sollten Zeichen mit Umlauten wie ä in der Nähe ihres Grundbuchstabens a sortiert werden, nicht am Ende. Das Problem liegt darin, dass JavaScript Unicode-Codepoint-Werte vergleicht, wobei Ä (U+00C4) nach Z (U+005A) kommt.
Verschiedene Sprachen haben unterschiedliche Sortierregeln. Schwedisch sortiert ä am Ende des Alphabets, Deutsch sortiert es in der Nähe von a, und Französisch behandelt akzentuierte Zeichen anders. Der binäre Vergleich ignoriert diese kulturellen Konventionen.
Wie String-Kollation funktioniert
Kollation ist der Prozess des Vergleichens und Ordnens von Strings nach sprachspezifischen Regeln. Der Unicode Collation Algorithm definiert, wie Strings verglichen werden, indem Zeichen, diakritische Zeichen, Groß-/Kleinschreibung und Interpunktion separat analysiert werden.
Beim Vergleich zweier Strings gibt eine Kollationsfunktion eine Zahl zurück:
- Negativer Wert: erster String kommt vor dem zweiten
- Null: Strings sind für die aktuelle Sensitivitätsstufe äquivalent
- Positiver Wert: erster String kommt nach dem zweiten
Dieses dreistufige Vergleichsmuster funktioniert mit Array.sort und ermöglicht eine präzise Kontrolle darüber, welche Unterschiede relevant sind.
Verwendung von localeCompare für grundlegende lokalisierungsorientierte Sortierung
Die localeCompare-Methode bietet einen lokalisierungsorientierten String-Vergleich:
const names = ["Zoe", "Ava", "Ärzte", "Änder"];
console.log(names.sort((a, b) => a.localeCompare(b, "de")));
// ["Ava", "Änder", "Ärzte", "Zoe"]
Dies erzeugt eine korrekte deutsche Sortierung. Der erste Parameter gibt die Locale an, und localeCompare behandelt die kulturellen Regeln automatisch.
Sie können Optionen als dritten Parameter übergeben:
const items = ["File10", "File2", "File1"];
console.log(items.sort((a, b) =>
a.localeCompare(b, "en", { numeric: true })
));
// ["File1", "File2", "File10"]
Die numeric-Option ermöglicht natürliches Sortieren, bei dem "2" vor "10" kommt. Ohne diese Option würde "10" vor "2" sortiert werden, da "1" vor "2" kommt.
Das Leistungsproblem bei wiederholtem localeCompare
Jeder localeCompare-Aufruf verarbeitet die Locale-Einstellungen von Grund auf neu. Beim Sortieren großer Arrays führt dies zu erheblichem Overhead:
// Ineffizient: verarbeitet Locale für jeden Vergleich
const sorted = items.sort((a, b) => a.localeCompare(b, "de"));
Das Sortieren von 1000 Elementen erfordert ungefähr 10000 Vergleiche. Jeder Vergleich erstellt die Locale-Konfiguration neu, was die Leistungskosten vervielfacht. Dieser Overhead wird in Benutzeroberflächen mit großen Datensätzen spürbar.
Verwendung von Intl.Collator für effiziente Zeichenkettenvergleiche
Intl.Collator erstellt ein wiederverwendbares Vergleichsobjekt, das die Locale-Einstellungen nur einmal verarbeitet:
const collator = new Intl.Collator("de");
const sorted = items.sort((a, b) => collator.compare(a, b));
Die Collator-Instanz speichert die Locale-Konfiguration und Vergleichsregeln. Die compare-Methode verwendet diese vorberechneten Regeln für jeden Vergleich und eliminiert so den wiederholten Initialisierungsaufwand.
Die Leistungsverbesserungen liegen zwischen 60% und 80% beim Sortieren großer Arrays im Vergleich zu wiederholten localeCompare-Aufrufen.
Direkter Zugriff auf die compare-Methode
Sie können die compare-Methode direkt an sort übergeben:
const collator = new Intl.Collator("de");
const sorted = items.sort(collator.compare);
Dies funktioniert, weil compare an die Collator-Instanz gebunden ist. Die Methode erhält zwei Zeichenketten und gibt das Vergleichsergebnis zurück, was der Signatur entspricht, die Array.sort erwartet.
Verständnis der Sensitivitätsstufen
Die sensitivity-Option steuert, welche Zeichenunterschiede beim Vergleich relevant sind. Es gibt vier Stufen:
Base-Sensitivität
Base-Sensitivität ignoriert Akzente und Groß-/Kleinschreibung:
const collator = new Intl.Collator("en", { sensitivity: "base" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // 0
console.log(collator.compare("a", "A")); // 0
console.log(collator.compare("a", "b")); // -1
Nur Grundbuchstaben unterscheiden sich. Diese Stufe eignet sich gut für unscharfe Suchen, bei denen Benutzer möglicherweise Akzente nicht korrekt eingeben.
Akzentsensitivität
Akzentsensitivität berücksichtigt Akzente, ignoriert aber Groß- und Kleinschreibung:
const collator = new Intl.Collator("en", { sensitivity: "accent" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // -1
console.log(collator.compare("a", "A")); // 0
console.log(collator.compare("á", "A")); // 1
Akzentuierte und nicht akzentuierte Zeichen unterscheiden sich. Groß- und Kleinbuchstaben des gleichen Buchstabens stimmen überein.
Groß-/Kleinschreibungssensitivität
Groß-/Kleinschreibungssensitivität berücksichtigt die Groß- und Kleinschreibung, ignoriert aber Akzente:
const collator = new Intl.Collator("en", { sensitivity: "case" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // 0
console.log(collator.compare("a", "A")); // -1
console.log(collator.compare("á", "Á")); // -1
Unterschiede in der Groß-/Kleinschreibung sind relevant, aber Akzente werden ignoriert. Diese Stufe ist in der Praxis weniger gebräuchlich.
Variantensensitivität
Variantensensitivität berücksichtigt alle Unterschiede:
const collator = new Intl.Collator("en", { sensitivity: "variant" });
console.log(collator.compare("a", "a")); // 0
console.log(collator.compare("a", "á")); // -1
console.log(collator.compare("a", "A")); // -1
console.log(collator.compare("á", "Á")); // -1
Dies ist die Standardeinstellung für die Sortierung. Jeder Zeichenunterschied erzeugt ein eindeutiges Vergleichsergebnis.
Auswahl der Sensitivität basierend auf dem Anwendungsfall
Verschiedene Szenarien erfordern unterschiedliche Sensitivitätsstufen:
- Sortieren von Listen: Verwenden Sie Variantensensitivität für eine strenge Sortierung
- Durchsuchen von Inhalten: Verwenden Sie Basissensitivität, um unabhängig von Akzenten oder Groß-/Kleinschreibung zu finden
- Filtern von Optionen: Verwenden Sie Akzentsensitivität, wenn Groß-/Kleinschreibung keine Rolle spielen soll
- Groß-/Kleinschreibung-sensitive Suche: Verwenden Sie Groß-/Kleinschreibungssensitivität, wenn Akzente keine Rolle spielen sollen
Die Usage-Option bietet Standardeinstellungen für Sensitivität für gängige Szenarien.
Verwendung von usage für Sortier- und Suchmodi
Die Usage-Option optimiert das Collator-Verhalten für Sortierung oder Suche:
// Optimiert für Sortierung
const sortCollator = new Intl.Collator("en", { usage: "sort" });
// Optimiert für Suche
const searchCollator = new Intl.Collator("en", { usage: "search" });
Die Sort-Usage verwendet standardmäßig Variantensensitivität, um sicherzustellen, dass jeder Unterschied eine konsistente Reihenfolge erzeugt. Die Search-Usage optimiert für das Finden von Übereinstimmungen, typischerweise mit einer entspannteren Sensitivität.
Für Groß-/Kleinschreibung- und Akzent-insensitive Suche:
const collator = new Intl.Collator("en", {
usage: "search",
sensitivity: "base"
});
const items = ["Apple", "Äpfel", "Banana"];
const matches = items.filter(item =>
collator.compare(item, "apple") === 0
);
console.log(matches); // ["Apple"]
Dieses Muster ermöglicht unscharfe Übereinstimmungen, bei denen Benutzer keine exakten Zeichen eingeben müssen.
Aktivierung der numerischen Sortierung für natürliche Reihenfolge
Die numerische Option behandelt eingebettete Zahlen als numerische Werte:
const collator = new Intl.Collator("en", { numeric: true });
const files = ["File1", "File10", "File2"];
console.log(files.sort(collator.compare));
// ["File1", "File2", "File10"]
Ohne numerische Sortierung würde "File10" vor "File2" sortiert werden, da die Zeichenfolge "10" mit "1" beginnt. Die numerische Sortierung analysiert Zahlensequenzen und vergleicht sie mathematisch.
Dies erzeugt eine natürliche Reihenfolge, die den menschlichen Erwartungen für Dateinamen, Versionsnummern und nummerierte Listen entspricht.
Umgang mit Dezimalzahlen bei numerischer Sortierung
Die numerische Sortierung hat eine Einschränkung bei Dezimalzahlen:
const collator = new Intl.Collator("en", { numeric: true });
const values = ["1.5", "1.10", "1.2"];
console.log(values.sort(collator.compare));
// ["1.2", "1.5", "1.10"]
Der Dezimalpunkt wird als Interpunktion behandelt, nicht als Teil der Zahl. Jedes Segment zwischen Interpunktionen wird separat sortiert. Für die Sortierung von Dezimalzahlen sollten Werte in Zahlen umgewandelt und numerisch verglichen werden.
Steuerung der Groß-/Kleinschreibungsreihenfolge mit caseFirst
Die caseFirst-Option bestimmt, ob Groß- oder Kleinbuchstaben zuerst sortiert werden:
// Großbuchstaben zuerst
const upperFirst = new Intl.Collator("en", { caseFirst: "upper" });
console.log(["a", "A", "b", "B"].sort(upperFirst.compare));
// ["A", "a", "B", "b"]
// Kleinbuchstaben zuerst
const lowerFirst = new Intl.Collator("en", { caseFirst: "lower" });
console.log(["a", "A", "b", "B"].sort(lowerFirst.compare));
// ["a", "A", "b", "B"]
Der Standardwert ist false, was die lokale Standardreihenfolge verwendet. Diese Option hat keine Auswirkung, wenn sensitivity auf base oder accent gesetzt ist, da diese Ebenen die Groß-/Kleinschreibung ignorieren.
Ignorieren von Interpunktion beim Vergleich
Die ignorePunctuation-Option überspringt Interpunktionszeichen beim Vergleich:
const collator = new Intl.Collator("en", { ignorePunctuation: true });
console.log(collator.compare("hello", "he-llo")); // 0
console.log(collator.compare("hello", "hello!")); // 0
Diese Option ist standardmäßig für Thai auf true und für andere Sprachen auf false gesetzt. Verwenden Sie sie, wenn Interpunktion die Zeichenfolgenreihenfolge oder -übereinstimmung nicht beeinflussen soll.
Spezifizierung von Kollationstypen für sprachspezifische Regeln
Einige Locales unterstützen mehrere Kollationstypen für spezialisierte Sortierungen:
// Chinesische Pinyin-Sortierung
const pinyin = new Intl.Collator("zh-CN-u-co-pinyin");
// Deutsche Telefonbuch-Sortierung
const phonebook = new Intl.Collator("de-DE-u-co-phonebk");
// Emoji-Gruppierung
const emoji = new Intl.Collator("en-u-co-emoji");
Der Kollationstyp wird in der Locale-Zeichenfolge mit Unicode-Erweiterungssyntax angegeben. Häufige Typen sind:
pinyin: Chinesische Sortierung nach romanisierter Aussprachestroke: Chinesische Sortierung nach Strichanzahlphonebk: Deutsche Telefonbuch-Sortierungtrad: Traditionelle Sortierregeln für bestimmte Sprachenemoji: Gruppiert Emojis nach Kategorie
Überprüfen Sie Intl.supportedValuesOf für verfügbare Kollationstypen in Ihrer Umgebung.
Wiederverwendung von Collator-Instanzen in Ihrer Anwendung
Erstellen Sie Collator-Instanzen einmal und verwenden Sie sie in Ihrer gesamten Anwendung wieder:
// utils/collation.js
export const germanCollator = new Intl.Collator("de");
export const searchCollator = new Intl.Collator("en", {
sensitivity: "base"
});
export const numericCollator = new Intl.Collator("en", {
numeric: true
});
// In Ihren Komponenten
import { germanCollator } from "./utils/collation";
const sorted = names.sort(germanCollator.compare);
Dieses Muster maximiert die Leistung und sorgt für ein konsistentes Vergleichsverhalten in Ihrem gesamten Codebase.
Sortieren von Arrays mit Objekten nach Eigenschaften
Verwenden Sie den Collator in einer Vergleichsfunktion, die auf Objekteigenschaften zugreift:
const collator = new Intl.Collator("de");
const users = [
{ name: "Zoe" },
{ name: "Änder" },
{ name: "Ava" }
];
const sorted = users.sort((a, b) =>
collator.compare(a.name, b.name)
);
Dieser Ansatz funktioniert für jede Objektstruktur. Extrahieren Sie die zu vergleichenden Zeichenketten und übergeben Sie sie an den Collator.
Vergleich der Leistung von Intl.Collator mit localeCompare
Intl.Collator bietet bessere Leistung beim Sortieren großer Datensätze:
// Langsamer: Erstellt Locale-Einstellungen für jeden Vergleich neu
const slow = items.sort((a, b) => a.localeCompare(b, "de"));
// Schneller: Wiederverwendet vorberechnete Locale-Einstellungen
const collator = new Intl.Collator("de");
const fast = items.sort(collator.compare);
Bei kleinen Arrays (unter 100 Elementen) ist der Unterschied vernachlässigbar. Bei großen Arrays (Tausende von Elementen) kann Intl.Collator 60-80% schneller sein.
Eine Ausnahme gibt es in V8-basierten Browsern wie Chrome. localeCompare verfügt über eine Optimierung für reine ASCII-Zeichenketten mittels Lookup-Tabellen. Bei der Sortierung von reinen ASCII-Zeichenketten kann localeCompare eine vergleichbare Leistung wie Intl.Collator erzielen.
Wann Intl.Collator versus localeCompare verwendet werden sollte
Verwenden Sie Intl.Collator wenn:
- Sie große Arrays sortieren (Hunderte oder Tausende von Elementen)
- Sie wiederholt sortieren (Benutzer wechselt Sortierreihenfolge, virtuelle Listen)
- Sie wiederverwendbare Vergleichsdienstprogramme erstellen
- Leistung für Ihren Anwendungsfall wichtig ist
Verwenden Sie localeCompare wenn:
- Sie einmalige Vergleiche durchführen
- Sie kleine Arrays sortieren (unter 100 Elemente)
- Einfachheit wichtiger ist als Leistungsbedenken
- Sie einen Inline-Vergleich ohne Setup benötigen
Beide APIs unterstützen die gleichen Optionen und liefern identische Ergebnisse. Der Unterschied liegt ausschließlich in der Leistung und Codeorganisation.
Überprüfung der aufgelösten Optionen
Die Methode resolvedOptions gibt die tatsächlich vom Collator verwendeten Optionen zurück:
const collator = new Intl.Collator("de", { sensitivity: "base" });
console.log(collator.resolvedOptions());
// {
// locale: "de",
// usage: "sort",
// sensitivity: "base",
// ignorePunctuation: false,
// collation: "default",
// numeric: false,
// caseFirst: "false"
// }
Dies hilft bei der Fehlersuche im Sortierverhalten und dem Verständnis der Standardwerte. Die aufgelöste Locale kann von der angeforderten Locale abweichen, wenn das System die exakte Locale nicht unterstützt.
Überprüfung der Locale-Unterstützung
Überprüfen Sie, welche Locales in der aktuellen Umgebung unterstützt werden:
const supported = Intl.Collator.supportedLocalesOf(["de", "fr", "xx"]);
console.log(supported); // ["de", "fr"]
Nicht unterstützte Locales fallen auf den Systemstandard zurück. Diese Methode hilft zu erkennen, wenn Ihre angeforderte Locale nicht verfügbar ist.
Browser- und Umgebungsunterstützung
Intl.Collator wird seit September 2017 weitgehend unterstützt. Alle modernen Browser und Node.js-Versionen unterstützen es. Die API funktioniert konsistent über verschiedene Umgebungen hinweg.
Einige Sortierungstypen und Optionen können in älteren Browsern nur begrenzt unterstützt werden. Testen Sie kritische Funktionalitäten oder überprüfen Sie die MDN-Kompatibilitätstabellen, wenn Sie ältere Umgebungen unterstützen.
Häufige Fehler, die vermieden werden sollten
Erstellen Sie nicht für jeden Vergleich einen neuen Collator:
// Falsch: erstellt Collator wiederholt
items.sort((a, b) => new Intl.Collator("de").compare(a, b));
// Richtig: einmal erstellen, wiederverwenden
const collator = new Intl.Collator("de");
items.sort(collator.compare);
Nehmen Sie nicht an, dass die Standardsortierung für internationalen Text funktioniert:
// Falsch: funktioniert nicht für Nicht-ASCII-Zeichen
names.sort();
// Richtig: verwenden Sie sprachbewusste Sortierung
names.sort(new Intl.Collator("de").compare);
Vergessen Sie nicht, die Empfindlichkeit für die Suche anzugeben:
// Falsch: Variantenempfindlichkeit erfordert exakte Übereinstimmung
const collator = new Intl.Collator("en");
items.filter(item => collator.compare(item, "apple") === 0);
// Richtig: Basisempfindlichkeit für unscharfe Übereinstimmung
const collator = new Intl.Collator("en", { sensitivity: "base" });
items.filter(item => collator.compare(item, "apple") === 0);
Praktische Anwendungsfälle
Verwenden Sie Intl.Collator für:
- Sortieren von benutzergenerierten Inhalten (Namen, Titel, Adressen)
- Implementierung von Such- und Autovervollständigungsfunktionen
- Erstellung von Datentabellen mit sortierbaren Spalten
- Erstellung von gefilterten Listen und Dropdown-Optionen
- Sortieren von Dateinamen und Versionsnummern
- Alphabetische Navigation in Kontaktlisten
- Mehrsprachige Anwendungsschnittstellen
Jede Benutzeroberfläche, die sortierten Text für Benutzer anzeigt, profitiert von sprachbewusster Kollation. Dies stellt sicher, dass Ihre Anwendung sich unabhängig von der Sprache des Benutzers nativ und korrekt anfühlt.