Signatur
Beschreibung
Die Funktion grapheme_levenshtein() berechnet die minimale Anzahl von Einfügungen, Ersetzungen und Löschungen, die nötig sind, um $str1 in $str2 umzuwandeln – wobei als Einheit Unicode-Graphem-Cluster verwendet werden. Ein Graphem-Cluster entspricht einem vom Benutzer wahrgenommenen Zeichen, also z. B. einem Basiszeichen zusammen mit zugehörigen Combining-Zeichen (Diakritika, Emojis mit Skin-Tone-Modifier etc.).
Dies ist der entscheidende Unterschied zu PHPs eingebauter levenshtein()-Funktion, die auf Bytes arbeitet, und zu mb_strlen()-basierten Ansätzen, die Codepunkte zählen. Bei Strings wie "e\u0301" (e + Combining Acute Accent) wird dies korrekt als ein einzelnes Graphem behandelt, sodass Vergleiche mit vorkomponiertem "é" realistische Distanzwerte liefern.
Die Funktion eignet sich besonders für Fuzzy-Suchen, Rechtschreibkorrekturen oder ähnlichkeitsbasierte Sortierungen in mehrsprachigen Anwendungen, bei denen korrekte Graphem-Segmentierung entscheidend ist. Die optionalen Kostenparameter erlauben eine Gewichtung der drei Grundoperationen unabhängig voneinander.
Die Funktion ist Teil der intl-Extension und erfordert, dass diese in PHP aktiviert ist.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $str1 Pflicht | string | Der erste UTF-8-kodierte Eingabe-String. | |
| $str2 Pflicht | string | Der zweite UTF-8-kodierte Eingabe-String, mit dem verglichen wird. | |
| $cost_ins | int | 1 | Kosten für eine Einfüge-Operation eines Graphem-Clusters. |
| $cost_rep | int | 1 | Kosten für eine Ersetzungs-Operation eines Graphem-Clusters. |
| $cost_del | int | 1 | Kosten für eine Löschungs-Operation eines Graphem-Clusters. |
Rückgabewert
0 bedeutet, dass beide Strings identisch sind (in Graphem-Clustern). Bei ungültiger UTF-8-Eingabe kann das Verhalten undefiniert sein.Beispiele
Einfacher Vergleich zweier ähnlicher Wörter
<?php
$dist = grapheme_levenshtein('Kitten', 'Sitten');
echo $dist; // 1 Ersetzung: K -> S
Korrekte Behandlung von Combining Characters
<?php
// 'e' + Combining Acute Accent (U+0301) vs. vorkomponierts 'é' (U+00E9)
$a = "cafe\u{0301}"; // Dekomponiert: 4 Grapheme (c, a, f, e+Akzent)
$b = "caf\u{00E9}"; // Vorkomponierts: 4 Grapheme (c, a, f, é)
$grapheme_dist = grapheme_levenshtein($a, $b);
$byte_dist = levenshtein($a, $b);
echo "Grapheme-Distanz: $grapheme_dist\n"; // 0 nach NFC-Normalisierung oder 0-1 je nach Normalisierungsstatus
echo "Byte-Distanz: $byte_dist\n"; // Kann stark abweichen
Rechtschreibkorrektur mit angepassten Operationskosten
<?php
$woerter = ['Haus', 'Maus', 'Klaus', 'Laus', 'Baum'];
$eingabe = 'Haus';
// Ersetzungen teurer gewichten als Einfügungen/Löschungen
usort($woerter, function ($a, $b) use ($eingabe) {
$da = grapheme_levenshtein($eingabe, $a, cost_ins: 1, cost_rep: 2, cost_del: 1);
$db = grapheme_levenshtein($eingabe, $b, cost_ins: 1, cost_rep: 2, cost_del: 1);
return $da <=> $db;
});
echo implode(', ', $woerter);
// Wichtig · Fallstricke
Voraussetzung: Die intl-Extension muss aktiviert sein (extension=intl in der php.ini). Andernfalls ist die Funktion nicht verfügbar.
Normalisierung: Die Funktion normalisiert Eingaben nicht automatisch. Strings in unterschiedlichen Unicode-Normalisierungsformen (NFC vs. NFD) können zu unerwarteten Distanzwerten führen. Es empfiehlt sich, Eingaben vor dem Vergleich mit Normalizer::normalize() in eine einheitliche Form zu bringen.
Performance: Der Algorithmus hat quadratische Zeit- und Speicherkomplexität (O(m·n)). Bei sehr langen Strings kann dies zu hohem Ressourcenverbrauch führen. Für produktiven Einsatz sollte ggf. eine Längenobergrenze geprüft werden.
Verfügbarkeit: Die Funktion wurde erst in PHP 8.4.0 eingeführt. In früheren PHP-Versionen muss auf Eigenimplementierungen oder alternative Bibliotheken zurückgegriffen werden.