Was ist der effizienteste Test, ob eine PHP-Zeichenfolge mit einer anderen Zeichenfolge endet?


125

Die Standard-PHP-Methode zum Testen, ob ein String $strmit einem Teilstring endet, $testist:

$endsWith = substr( $str, -strlen( $test ) ) == $test

Ist das der schnellste Weg?



Antworten:


152

Was Assaf gesagt hat, ist richtig. In PHP ist eine Funktion integriert, um genau das zu tun.

substr_compare($str, $test, strlen($str)-strlen($test), strlen($test)) === 0;

Wenn $testes länger als $strPHP ist, wird eine Warnung ausgegeben, daher müssen Sie dies zuerst überprüfen.

function endswith($string, $test) {
    $strlen = strlen($string);
    $testlen = strlen($test);
    if ($testlen > $strlen) return false;
    return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
}

Nett. Es scheint, als wäre ein Vergleich vor Ort schneller als substr (), wie Assaf betonte.
Jason Cohen

2
Die Antwort von mcrumley ist cool, sollte aber '===' anstelle von '==' verwenden. '===' ist strenger und macht normalerweise das, was Sie wollen, während '==' zu bösen Überraschungen führen kann. Das dritte Code-Snippet von mcrumley ist korrekt, die ersten beiden jedoch nicht. substr_compare () gibt in einigen Fehlerfällen false zurück. In PHP ist false == 0, sodass die Codefragmente signalisieren, dass die Zeichenfolge gefunden wurde. Mit === passiert das nicht.
jcsahnwaldt Reinstate Monica

1
Ich bin heute auf einen Fehler gestoßen, der die Lösung, die Sie ab PHP 5.5.11 gegeben haben, beschädigt. bugs.php.net/bug.php?id=67043
user2180613

3 Funktionsaufrufe machen es nicht am schnellsten.
Thanh Trung

66

Diese Methode ist ein bisschen speicherintensiver, aber schneller:

stripos(strrev($haystack), $reversed_needle) === 0;

Dies ist am besten, wenn Sie genau wissen, was die Nadel ist, damit Sie sie umgekehrt hart codieren können. Wenn Sie die Nadel programmgesteuert umkehren, wird sie langsamer als die vorherige Methode.


2
-1 Ich bezweifle ernsthaft, dass dies schneller und schwieriger ist (cool, aber normalerweise nicht hilfreich). Wenn der Heuhaufen nicht mit der Nadel endet, striposwird im schlimmsten Fall die gesamte Schnur iteriert, während substr_comparehöchstens die Länge der Nadel verglichen wird. Ja, substr_compareerfordert die Berechnung der Länge des Heuhaufens (und der viel kleineren Nadel), aber diese Methode erfordert dies und das vollständige Kopieren und möglicherweise das Konvertieren des gesamten Objekts in Kleinbuchstaben zum Booten.
David Harkness

cooler Ansatz, aber in vielen Fällen ineffizient (wie in der Antwort selbst erwähnt)! Immer noch eine Gegenstimme dafür, seltsam kreativ zu sein und zu demonstrieren, dass es immer mehr Möglichkeiten geben kann, dasselbe zu tun, als Sie sich jemals vorstellen können. Prost!
Fr0zenFyr

1
Ich habe diese Methode getestet und finde sie schneller als die akzeptierte Antwort. Selbst wenn sowohl der Heuhaufen als auch die Nadel im laufenden Betrieb umgekehrt werden, ist dies schneller.
Shumoapp

@ DavidHarkness Haben Sie getestet, ob Ihre Zweifel berechtigt waren?
Nathan

@ Nathan Nein, es ist die Zeit zum Benchmarking nicht wert, da es gut substr_compare()funktioniert.
David Harkness

61
$endsWith = substr_compare( $str, $test, -strlen( $test ) ) === 0

Negativer Offset "beginnt am Ende der Zeichenfolge zu zählen".


3
IMO ist es eine der besten aus den bereitgestellten Lösungen
Roman Podlinov

+200 wenn ich könnte. Die wichtigste Erkenntnis hier ist, dass die Verwendung einer negativen Länge den Endteil der Zeichenfolge erhält. Sie können auch substr mit der Länge -ve verwenden und == gegen $ test ausführen. Die anderen Antworten sind schlecht.
Nick

11

Hier ist eine einfache Möglichkeit, um zu überprüfen, ob eine Zeichenfolge mit einer anderen endet, indem Sie strposeinen Versatz genau dort angeben, wo die Zeichenfolge gefunden werden soll:

function stringEndsWith($whole, $end)
{
    return (strpos($whole, $end, strlen($whole) - strlen($end)) !== false);
}

Einfach, und ich denke, das wird in PHP 4 funktionieren.


8

Es hängt davon ab, welche Art von Effizienz Sie interessiert.

Ihre Version benötigt aufgrund der zusätzlichen Kopie aus der Verwendung von substr mehr Speicher.

Eine alternative Version durchsucht möglicherweise die ursprüngliche Zeichenfolge nach dem letzten Vorkommen des Teilstrings, ohne eine Kopie zu erstellen, ist jedoch aufgrund weiterer Tests wahrscheinlich langsamer.

Der wahrscheinlich effizienteste Weg ist es, eine Schleife von Zeichen zu Zeichen von der Position -sterlen (Test) bis zum Ende des Strings durchzuführen und zu vergleichen. Das ist die minimale Anzahl von Vergleichen, auf die Sie hoffen können, und es wird kaum zusätzlicher Speicher verwendet.



3

Ich hoffe, dass die folgende Antwort effizient und auch einfach sein kann:

$content = "The main string to search";
$search = "search";
//For compare the begining string with case insensitive. 
if(stripos($content, $search) === 0) echo 'Yes';
else echo 'No';

//For compare the begining string with case sensitive. 
if(strpos($content, $search) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case insensitive. 
if(stripos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case sensitive. 
if(strpos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';

2

Ich weiß nicht, ob das schnell geht oder nicht, aber für einen einzelnen Zeichentest funktionieren auch diese:

(array_pop(str_split($string)) === $test) ? true : false;
($string[strlen($string)-1] === $test) ? true : false;
(strrev($string)[0] === $test) ? true : false;

1

einfachste Möglichkeit, dies über reguläre Ausdrücke zu überprüfen

Um beispielsweise zu überprüfen, ob es sich bei der angegebenen E-Mail um Google Mail handelt:

echo (preg_match("/@gmail\.com$/","example-email@gmail.com"))?'true':'false';

0

Ich denke, die umgekehrten Funktionen wie strrchr () würden Ihnen helfen, das Ende des Strings am schnellsten zu finden.


0

Dies ist reines PHP, ohne externe Funktionen aufzurufen, außer strlen .

function endsWith ($ends, $string)
{
    $strLength = strlen ($string);
    $endsLength = strlen ($ends);
    for ($i = 0; $i < $endsLength; $i++)
    {
        if ($string [$strLength - $i - 1] !== $ends [$i])
            return false;
    }
    return true;
}

0

für Single-Char-Nadel:

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.