Start · Sprachen · PHP · Referenz · grapheme_levenshtein

grapheme_levenshtein

Funktion

Berechnet die Levenshtein-Distanz zwischen zwei Strings auf Basis von Unicode-Graphem-Clustern (nicht Bytes oder Codepunkte).

seit PHP 8.4.0 Kategorie: string

Signatur

grapheme_levenshtein(string $str1, string $str2, int $cost_ins = 1, int $cost_rep = 1, int $cost_del = 1): int

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

Typ
int
Beschreibung
Gibt die berechnete Levenshtein-Distanz als nicht-negative ganze Zahl zurück. Der Wert 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
1

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
Grapheme-Distanz: 0 Byte-Distanz: 1

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);
Haus, Maus, Laus, Klaus, Baum

// 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.