Schnelle Stringvergleichsfunktion für PHP
Hallo User,
als Entwickler stand ich vor einer Herausforderung: Ich brauchte eine schnelle Stringvergleichsfunktion für unsere Website. Meine Reise begann mit den PHP-Funktionen similar_text() und später levenshtein(). Doch selbst diese nativen Funktionen brauchten bei längeren Texten über 30 Sekunden – viel zu lang für unsere Webseite.
Die Suche nach einer effizienteren Lösung führte mich zu einer einfachen, aber äußerst effektiven Methode. Statt komplexer Algorithmen nutze ich nun grundlegende Textverarbeitungsmethoden wie Längenvergleich und Wortzählung. Das Ergebnis? Eine beeindruckende Performancesteigerung von 80% bis 90% gegenüber similar_text() und levenshtein()
Meine neue stringCompare()-Funktion vergleicht zwei Texte ($str1, $str2) und gibt den Unterschied in Prozent aus. Sie ist nicht nur schnell, sondern auch leicht zu verstehen und zu implementieren. Hundertprozentig genau ist sie jedoch nicht (je nach Länge des Textes sind Abweichungen im einstelligen Bereich möglich). Die Funktion konzentriert sich mehr auf quantitative Aspekte (Länge, Worthäufigkeit) als auf qualitative Aspekte (Bedeutung, Kontext). Sie ist effektiv darin, strukturelle Ähnlichkeiten und wörtliche Übereinstimmungen zu erkennen, aber sie kann subtilere inhaltliche Unterschiede oder Ähnlichkeiten übersehen.
Ich möchte diese Lösung mit der Entwickler-Community teilen, in der Hoffnung, dass sie bei ähnlichen Performance-Problemen helfen kann.
UPDATE: Es gibt mehrere verbesserte Versionen des Codes weiter unten. "cleanString" und die "Beispielaufrufe" sind jedoch identisch.
Gruß
Frank
als Entwickler stand ich vor einer Herausforderung: Ich brauchte eine schnelle Stringvergleichsfunktion für unsere Website. Meine Reise begann mit den PHP-Funktionen similar_text() und später levenshtein(). Doch selbst diese nativen Funktionen brauchten bei längeren Texten über 30 Sekunden – viel zu lang für unsere Webseite.
Die Suche nach einer effizienteren Lösung führte mich zu einer einfachen, aber äußerst effektiven Methode. Statt komplexer Algorithmen nutze ich nun grundlegende Textverarbeitungsmethoden wie Längenvergleich und Wortzählung. Das Ergebnis? Eine beeindruckende Performancesteigerung von 80% bis 90% gegenüber similar_text() und levenshtein()
Meine neue stringCompare()-Funktion vergleicht zwei Texte ($str1, $str2) und gibt den Unterschied in Prozent aus. Sie ist nicht nur schnell, sondern auch leicht zu verstehen und zu implementieren. Hundertprozentig genau ist sie jedoch nicht (je nach Länge des Textes sind Abweichungen im einstelligen Bereich möglich). Die Funktion konzentriert sich mehr auf quantitative Aspekte (Länge, Worthäufigkeit) als auf qualitative Aspekte (Bedeutung, Kontext). Sie ist effektiv darin, strukturelle Ähnlichkeiten und wörtliche Übereinstimmungen zu erkennen, aber sie kann subtilere inhaltliche Unterschiede oder Ähnlichkeiten übersehen.
Ich möchte diese Lösung mit der Entwickler-Community teilen, in der Hoffnung, dass sie bei ähnlichen Performance-Problemen helfen kann.
class TextComparison {
public static function stringCompare($str1, $str2): float {
// Frühe Rückkehr für identische Strings
if ($str1 === $str2) {
return 0.0;
}
// Normalisierung, reinige die Strings (optional)
$str1 = self::cleanString($str1);
$str2 = self::cleanString($str2);
// Prüfe auf leere Strings nach der Reinigung
if ($str1 === '' && $str2 === '') {
return 0.0;
}
if ($str1 === '' || $str2 === '') {
return 100.0;
}
// Berechne Längenänderung
$len1 = strlen($str1);
$len2 = strlen($str2);
$lengthChange = abs($len2 - $len1) / max($len1, $len2);
// Berechne Wortübereinstimmung
$words1 = str_word_count(mb_strtolower($str1), 1);
$words2 = str_word_count(mb_strtolower($str2), 1);
$uniqueWords = array_unique(array_merge($words1, $words2));
$matchingWords = 0;
foreach ($uniqueWords as $word) {
$count1 = array_count_values($words1)[$word] ?? 0;
$count2 = array_count_values($words2)[$word] ?? 0;
$matchingWords += min($count1, $count2);
}
$totalWords = max(count($words1), count($words2));
$wordChange = 1 - ($matchingWords / $totalWords);
// Kombiniere Längen- und Wortänderung
$overallChange = ($lengthChange + $wordChange) / 2;
// Ausgabe in Prozent
return round($overallChange * 100, 2);
}
private static function cleanString($string): string {
// Entferne Satzzeichen und sonstige nicht-alphanumerische Zeichen (optional)
return preg_replace('/[^a-zA-Z0-9\s]/u', '', $string);
}
}
// Beispielaufrufe
$str1 = "Dies ist ein Beispieltext für den Vergleich.";
$str2 = "Dies ist ein Beispieltext für den Vergleich. Dies ist ein Beispieltext für den Vergleich.";
$str3 = "Dies ist ein völlig anderer Text.";
echo "Änderungsprozentsatz (verdoppelter Text): " . TextComparison::stringCompare($str1, $str2) . "%\n";
echo "Änderungsprozentsatz (unterschiedlicher Text): " . TextComparison::stringCompare($str1, $str3) . "%\n";
echo "Änderungsprozentsatz (identischer Text): " . TextComparison::stringCompare($str1, $str1) . "%\n";
UPDATE: Es gibt mehrere verbesserte Versionen des Codes weiter unten. "cleanString" und die "Beispielaufrufe" sind jedoch identisch.
Gruß
Frank
Please also mark the comments that contributed to the solution of the article
Content-ID: 668057
Url: https://administrator.de/contentid/668057
Printed on: October 15, 2024 at 05:10 o'clock
6 Comments
Latest comment
Moin.
👍 . Kommt darauf an wie man hier die "Menge an Änderung" definiert, wenn ich etwa beispielsweise alle Zeichen durch "x" ersetze, Länge lasse ich gleich, habe ich eigentlich nach meiner Definition alles abgeändert (außer der Leerzeichen) der Prozentsatz beträgt dann aber nur 52,27 %
https://tio.run/##jVXbTttAEH3PV4wiCk5JSPBbkyJEafvSqqqgKhKXRhtnHK9Yr93dNV ...
Noch als Verbesserungsvorschlag
Gruß
👍 . Kommt darauf an wie man hier die "Menge an Änderung" definiert, wenn ich etwa beispielsweise alle Zeichen durch "x" ersetze, Länge lasse ich gleich, habe ich eigentlich nach meiner Definition alles abgeändert (außer der Leerzeichen) der Prozentsatz beträgt dann aber nur 52,27 %
$str1 = "Dies ist ein Beispieltext für den Vergleich.";
$str2 = "xxxx xxx xxx xxxxxxxxxxxx xxx xxx xxxxxxxxxx";
echo "Änderungsprozentsatz " . TextComparison::stringCompare($str1, $str2) . "%";
Noch als Verbesserungsvorschlag
array_count_values($words1)
array_count_values($words2)
Die Ergebnisse der zwei Funktionsaufrufe könnte man vor der Schleife noch zwischenspeichern so das sie nicht für jeden Schleifenaufruf erneut berechnet werden müssen, das täte der Performance auch noch gut.array_count_values($words2)
Gruß
Noch 30 Versuche dann ist die schneller als das Licht bzw. kommt die Antwort schon vor der Frage
Gruss,
Peter
Gruss,
Peter