Zeichenketten unter Ignorierung von Akzentzeichen vergleichen
Erfahren Sie, wie Sie Zeichenketten unter Ignorierung diakritischer Zeichen mithilfe von JavaScript-Normalisierung und Intl.Collator vergleichen
Einführung
Beim Erstellen von Anwendungen, die mit mehreren Sprachen arbeiten, müssen Sie häufig Zeichenketten vergleichen, die Akzentzeichen enthalten. Ein Benutzer, der nach "cafe" sucht, sollte Ergebnisse für "café" finden. Eine Benutzernamenprüfung für "Jose" sollte mit "José" übereinstimmen. Der standardmäßige Zeichenkettenvergleich behandelt diese als unterschiedliche Zeichenketten, aber Ihre Anwendungslogik muss sie als gleich behandeln.
JavaScript bietet zwei Ansätze zur Lösung dieses Problems. Sie können Zeichenketten normalisieren und Akzentzeichen entfernen oder die integrierte Collation-API verwenden, um Zeichenketten mit spezifischen Sensitivitätsregeln zu vergleichen.
Was sind Akzentzeichen
Akzentzeichen sind Symbole, die über, unter oder durch Buchstaben platziert werden, um deren Aussprache oder Bedeutung zu ändern. Diese Zeichen werden als Diakritika bezeichnet. Häufige Beispiele sind der Akut in "é", die Tilde in "ñ" und das Umlaut in "ü".
In Unicode können diese Zeichen auf zwei Arten dargestellt werden. Ein einzelner Code-Point kann das vollständige Zeichen darstellen, oder mehrere Code-Points können einen Basisbuchstaben mit einem separaten Akzentzeichen kombinieren. Der Buchstabe "é" kann als U+00E9 oder als "e" (U+0065) plus einem kombinierenden Akut (U+0301) gespeichert werden.
Wann Akzentzeichen bei Vergleichen ignoriert werden sollten
Suchfunktionalität ist der häufigste Anwendungsfall für akzentunempfindliche Vergleiche. Benutzer, die Suchanfragen ohne Akzentzeichen eingeben, erwarten, Inhalte zu finden, die akzentuierte Zeichen enthalten. Eine Suche nach "Muller" sollte "Müller" finden.
Die Validierung von Benutzereingaben erfordert diese Fähigkeit bei der Überprüfung, ob Benutzernamen, E-Mail-Adressen oder andere Identifikatoren bereits existieren. Sie möchten doppelte Konten für "maria" und "maría" verhindern.
Bei Vergleichen ohne Berücksichtigung der Groß- und Kleinschreibung müssen oft gleichzeitig Akzente ignoriert werden. Wenn Sie prüfen, ob zwei Zeichenketten unabhängig von der Groß- und Kleinschreibung übereinstimmen, möchten Sie in der Regel auch Akzentunterschiede ignorieren.
Akzentzeichen mittels Normalisierung entfernen
Der erste Ansatz konvertiert Zeichenketten in eine normalisierte Form, bei der Grundbuchstaben und Akzentzeichen getrennt werden, und entfernt dann die Akzentzeichen.
Die Unicode-Normalisierung konvertiert Zeichenketten in eine Standardform. Die NFD-Form (Canonical Decomposition) trennt kombinierte Zeichen in ihre Grundbuchstaben und kombinierenden Zeichen. Die Zeichenkette "café" wird zu "cafe" gefolgt von einem kombinierenden Akut-Akzent-Zeichen.
Nach der Normalisierung können Sie die kombinierenden Zeichen mithilfe eines regulären Ausdrucks entfernen. Der Unicode-Bereich U+0300 bis U+036F enthält kombinierende diakritische Zeichen.
function removeAccents(str) {
return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
const text1 = 'café';
const text2 = 'cafe';
const normalized1 = removeAccents(text1);
const normalized2 = removeAccents(text2);
console.log(normalized1 === normalized2); // true
console.log(normalized1); // "cafe"
Diese Methode liefert Ihnen Zeichenketten ohne Akzentzeichen, die Sie mit Standard-Gleichheitsoperatoren vergleichen können.
Sie können dies mit der Kleinbuchstabenkonvertierung für Vergleiche ohne Berücksichtigung von Groß- und Kleinschreibung sowie Akzenten kombinieren.
function normalizeForComparison(str) {
return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase();
}
const search = 'muller';
const name = 'Müller';
console.log(normalizeForComparison(search) === normalizeForComparison(name)); // true
Dieser Ansatz funktioniert gut, wenn Sie die normalisierte Version von Zeichenketten für effizientes Suchen speichern oder indizieren müssen.
Zeichenketten mittels Intl.Collator vergleichen
Der zweite Ansatz verwendet die Intl.Collator-API, die einen sprachbewussten Zeichenkettenvergleich mit konfigurierbaren Empfindlichkeitsstufen bietet.
Das Intl.Collator-Objekt vergleicht Zeichenketten nach sprachspezifischen Regeln. Die Sensitivity-Option steuert, welche Unterschiede beim Vergleich von Zeichenketten relevant sind.
Die Empfindlichkeitsstufe "base" ignoriert sowohl Akzentzeichen als auch Unterschiede in der Groß- und Kleinschreibung. Zeichenketten, die sich nur in Akzenten oder Großschreibung unterscheiden, werden als gleich betrachtet.
const collator = new Intl.Collator('en', { sensitivity: 'base' });
console.log(collator.compare('café', 'cafe')); // 0 (equal)
console.log(collator.compare('Café', 'cafe')); // 0 (equal)
console.log(collator.compare('café', 'caff')); // -1 (first comes before second)
Die compare-Methode gibt 0 zurück, wenn Zeichenketten gleich sind, eine negative Zahl, wenn die erste Zeichenkette vor der zweiten kommt, und eine positive Zahl, wenn die erste Zeichenkette nach der zweiten kommt.
Sie können dies für Gleichheitsprüfungen oder zum Sortieren von Arrays verwenden.
const collator = new Intl.Collator('en', { sensitivity: 'base' });
function areEqualIgnoringAccents(str1, str2) {
return collator.compare(str1, str2) === 0;
}
console.log(areEqualIgnoringAccents('José', 'Jose')); // true
console.log(areEqualIgnoringAccents('naïve', 'naive')); // true
Zum Sortieren können Sie die compare-Methode direkt an Array.sort übergeben.
const names = ['Müller', 'Martinez', 'Muller', 'Márquez'];
const collator = new Intl.Collator('en', { sensitivity: 'base' });
names.sort(collator.compare);
console.log(names); // Groups variants together
Die Intl.Collator-API bietet weitere Sensitivitätsstufen für verschiedene Anwendungsfälle.
Die Stufe "accent" ignoriert Groß-/Kleinschreibung, berücksichtigt jedoch Akzentunterschiede. "Café" entspricht "café", aber nicht "cafe".
const accentCollator = new Intl.Collator('en', { sensitivity: 'accent' });
console.log(accentCollator.compare('Café', 'café')); // 0 (equal)
console.log(accentCollator.compare('café', 'cafe')); // 1 (not equal)
Die Stufe "case" ignoriert Akzente, berücksichtigt jedoch Unterschiede in der Groß-/Kleinschreibung. "café" entspricht "cafe", aber nicht "Café".
const caseCollator = new Intl.Collator('en', { sensitivity: 'case' });
console.log(caseCollator.compare('café', 'cafe')); // 0 (equal)
console.log(caseCollator.compare('café', 'Café')); // -1 (not equal)
Die Stufe "variant" berücksichtigt alle Unterschiede. Dies ist das Standardverhalten.
const variantCollator = new Intl.Collator('en', { sensitivity: 'variant' });
console.log(variantCollator.compare('café', 'cafe')); // 1 (not equal)
Wahl zwischen Normalisierung und Kollation
Beide Methoden liefern korrekte Ergebnisse für akzentunabhängige Vergleiche, weisen jedoch unterschiedliche Eigenschaften auf.
Die Normalisierungsmethode erstellt neue Strings ohne Akzentzeichen. Verwenden Sie diesen Ansatz, wenn Sie die normalisierten Versionen speichern oder indizieren müssen. Suchmaschinen und Datenbanken speichern häufig normalisierten Text für effiziente Abfragen.
Die Intl.Collator-Methode vergleicht Strings, ohne sie zu verändern. Verwenden Sie diesen Ansatz, wenn Sie Strings direkt vergleichen müssen, beispielsweise beim Prüfen auf Duplikate oder beim Sortieren von Listen. Der Collator berücksichtigt sprachspezifische Sortierregeln, die ein einfacher String-Vergleich nicht handhaben kann.
Leistungsaspekte variieren je nach Anwendungsfall. Das einmalige Erstellen eines Collator-Objekts und dessen Wiederverwendung ist effizient für mehrere Vergleiche. Das Normalisieren von Strings ist effizient, wenn Sie einmal normalisieren und viele Male vergleichen.
Die Normalisierungsmethode entfernt Akzentinformationen dauerhaft. Die Kollationsmethode bewahrt die ursprünglichen Strings, während sie diese gemäß den von Ihnen festgelegten Regeln vergleicht.
Filtern von Arrays mit akzentunabhängiger Suche
Ein häufiger Anwendungsfall ist das Filtern eines Arrays von Elementen basierend auf Benutzereingaben unter Ignorierung von Akzentunterschieden.
const products = [
{ name: 'Café Latte', price: 4.50 },
{ name: 'Crème Brûlée', price: 6.00 },
{ name: 'Croissant', price: 3.00 },
{ name: 'Café Mocha', price: 5.00 }
];
function searchProducts(query) {
const collator = new Intl.Collator('en', { sensitivity: 'base' });
return products.filter(product => {
return collator.compare(product.name.slice(0, query.length), query) === 0;
});
}
console.log(searchProducts('cafe'));
// Returns both Café Latte and Café Mocha
Für Teilstring-Matching funktioniert der Normalisierungsansatz besser.
function removeAccents(str) {
return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}
function searchProducts(query) {
const normalizedQuery = removeAccents(query.toLowerCase());
return products.filter(product => {
const normalizedName = removeAccents(product.name.toLowerCase());
return normalizedName.includes(normalizedQuery);
});
}
console.log(searchProducts('creme'));
// Returns Crème Brûlée
Dieser Ansatz prüft, ob der normalisierte Produktname die normalisierte Suchanfrage als Teilstring enthält.
Texteingabe-Matching handhaben
Bei der Validierung von Benutzereingaben gegen vorhandene Daten benötigen Sie einen akzentunabhängigen Vergleich, um Verwirrung und Duplikate zu vermeiden.
const existingUsernames = ['José', 'María', 'François'];
function isUsernameTaken(username) {
const collator = new Intl.Collator('en', { sensitivity: 'base' });
return existingUsernames.some(existing =>
collator.compare(existing, username) === 0
);
}
console.log(isUsernameTaken('jose')); // true
console.log(isUsernameTaken('Maria')); // true
console.log(isUsernameTaken('francois')); // true
console.log(isUsernameTaken('pierre')); // false
Dies verhindert, dass Benutzer Konten mit Namen erstellen, die sich von bestehenden Konten nur durch Akzente oder Groß-/Kleinschreibung unterscheiden.
Browser- und Umgebungsunterstützung
Die String.prototype.normalize-Methode wird in allen modernen Browsern und Node.js-Umgebungen unterstützt. Internet Explorer unterstützt diese Methode nicht.
Die Intl.Collator-API wird in allen modernen Browsern und Node.js-Versionen unterstützt. Internet Explorer 11 bietet teilweise Unterstützung.
Beide Ansätze funktionieren zuverlässig in aktuellen JavaScript-Umgebungen. Wenn Sie ältere Browser unterstützen müssen, benötigen Sie Polyfills oder alternative Implementierungen.
Einschränkungen der Akzententfernung
Einige Sprachen verwenden diakritische Zeichen, um eigenständige Buchstaben zu bilden, nicht nur Akzentvariationen. Im Türkischen sind "i" und "ı" unterschiedliche Buchstaben. Im Deutschen ist "ö" ein eigenständiger Vokal, nicht ein akzentuiertes "o".
Das Entfernen von Akzenten verändert in diesen Fällen die Bedeutung. Überlegen Sie, ob ein akzentunabhängiger Vergleich für Ihren Anwendungsfall und die Zielsprachen angemessen ist.
Der Collation-Ansatz behandelt diese Fälle besser, da er sprachspezifischen Regeln folgt. Die Angabe der korrekten Locale im Intl.Collator-Konstruktor gewährleistet kulturell angemessene Vergleiche.
const turkishCollator = new Intl.Collator('tr', { sensitivity: 'base' });
const germanCollator = new Intl.Collator('de', { sensitivity: 'base' });
Berücksichtigen Sie immer die Sprachen, die Ihre Anwendung unterstützt, wenn Sie eine Vergleichsstrategie wählen.