Starts mit () und Enden mit () Funktionen in PHP

1480

Wie kann ich zwei Funktionen schreiben, die eine Zeichenfolge annehmen und zurückgeben, wenn sie mit dem angegebenen Zeichen / der angegebenen Zeichenfolge beginnt oder damit endet?

Zum Beispiel:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
Klicken Sie auf Upvote
quelle
19
In der Str-Klasse von Laravel StartWith () und EndsWith () finden Sie bewährte Methoden. Es wurden Randfälle festgestellt, daher ist die weit verbreitete Verwendung dieses Codes von Vorteil.
Gras Double
1
Möglicherweise finden Sie s($str)->startsWith('|')und s($str)->endsWith('}')hilfreich, wie in dieser eigenständigen Bibliothek gefunden .
Caw
3
Warnung: Die meisten Antworten hier sind bei Multi-Byte-Codierungen wie UTF-8 unzuverlässig.
Álvaro González
Wenn Sie meinem obigen Kommentar folgen, können Sie sicherstellen, dass Sie die neueste Version verwenden (Stand heute, 5.4 ). Insbesondere wurde startWith () für große Heuhaufen-Strings optimiert.
Gras Double

Antworten:

1612
function startsWith($haystack, $needle)
{
     $length = strlen($needle);
     return (substr($haystack, 0, $length) === $needle);
}

function endsWith($haystack, $needle)
{
    $length = strlen($needle);
    if ($length == 0) {
        return true;
    }

    return (substr($haystack, -$length) === $needle);
}

Verwenden Sie diese Option, wenn Sie keinen regulären Ausdruck verwenden möchten.

MrHus
quelle
16
+1 Dies ist sauberer als die akzeptierte Antwort. Auch $lengthwird in der letzten Zeile der nicht benötigt endsWith().
zu viel PHP
13
Ich würde endenWits ('foo', '') == false ist das richtige Verhalten. Weil foo nicht mit nichts endet. 'Foo' endet mit 'o', 'oo' und 'Foo'.
MrHus
125
EndsWith kann viel kürzer geschrieben werden:return substr($haystack, -strlen($needle))===$needle;
Rok Kralj
12
Sie können dies ifinsgesamt vermeiden, indem Sie $lengthals dritten Parameter Folgendes übergeben substr: return (substr($haystack, -$length, $length);. Dies behandelt den Fall, $length == 0indem eine leere Zeichenfolge und nicht die gesamte zurückgegeben wird $haystack.
mxxk
20
@ MrHus Ich würde empfehlen, Multi-Byte-sichere Funktionen zu verwenden, z. B. mb_strlen und mb_substr
19Gerhard85
1024

Mit der substr_compareFunktion können Sie Anfang und Ende überprüfen mit:

function startsWith($haystack, $needle) {
    return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}
function endsWith($haystack, $needle) {
    return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}

Dies sollte eine der schnellsten Lösungen für PHP 7 ( Benchmark-Skript ) sein. Getestet gegen 8KB Heuhaufen, Nadeln unterschiedlicher Länge und volle, teilweise und keine Streichhölzer. strncmpist für Anfänge eine Berührung schneller, kann aber die Enden nicht überprüfen.

Salman A.
quelle
74
Diese Antwort hat es in die Daily WTF geschafft! : D Siehe thedailywtf.com/articles/…
Wim ten Brink
Bitte beachten Sie, dass die Kommentare @DavidWallace und @FrancescoMM für eine ältere Version dieser Antwort gelten. Die aktuelle Antwort verwendet, strrposwas sofort fehlschlagen sollte, wenn die Nadel nicht zum Beginn des Heuhaufens passt.
Salman A
2
Ich verstehe es nicht Basierend auf php.net/manual/en/function.strrpos.php : "Wenn der Wert negativ ist, beginnt die Suche stattdessen mit so vielen Zeichen am Ende der Zeichenfolge und sucht rückwärts." Dies scheint darauf hinzudeuten, dass wir bei Zeichen 0 beginnen (aufgrund von -strlength($haystack)) und von dort aus rückwärts suchen ? Bedeutet das nicht, dass Sie nichts suchen? Ich verstehe auch die !== falseTeile davon nicht. Ich vermute, dies beruht auf einer Eigenart von PHP, bei der einige Werte "wahr" und andere "falsch" sind, aber wie funktioniert das in diesem Fall?
Welbog
3
@Welbog: Zum Beispiel Heuhaufen = xxxyyyNadel = yyyund strrposdie Suche beginnt von der ersten x. Jetzt haben wir hier keine erfolgreiche Übereinstimmung (x statt y gefunden) und wir können nicht mehr rückwärts gehen (wir stehen am Anfang der Zeichenfolge). Die Suche schlägt sofort fehl . Informationen zur Verwendung von !== false- strrposim obigen Beispiel wird 0 oder false und kein anderer Wert zurückgegeben. Ebenso kann strposim obigen Beispiel $temp(die erwartete Position) oder false zurückgegeben werden. Ich habe mich !== falsefür Konsistenz entschieden, aber Sie konnten === 0bzw. === $tempin den Funktionen verwenden.
Salman A
8
@spoo Es wurde bereits festgestellt, dass strpos === 0 eine schreckliche Lösung ist, wenn der Heuhaufen groß ist und keine Nadel vorhanden ist.
Salman A
243

Aktualisiert am 23.08.2016

Funktionen

function substr_startswith($haystack, $needle) {
    return substr($haystack, 0, strlen($needle)) === $needle;
}

function preg_match_startswith($haystack, $needle) {
    return preg_match('~' . preg_quote($needle, '~') . '~A', $haystack) > 0;
}

function substr_compare_startswith($haystack, $needle) {
    return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}

function strpos_startswith($haystack, $needle) {
    return strpos($haystack, $needle) === 0;
}

function strncmp_startswith($haystack, $needle) {
    return strncmp($haystack, $needle, strlen($needle)) === 0;
}

function strncmp_startswith2($haystack, $needle) {
    return $haystack[0] === $needle[0]
        ? strncmp($haystack, $needle, strlen($needle)) === 0
        : false;
}

Tests

echo 'generating tests';
for($i = 0; $i < 100000; ++$i) {
    if($i % 2500 === 0) echo '.';
    $test_cases[] = [
        random_bytes(random_int(1, 7000)),
        random_bytes(random_int(1, 3000)),
    ];
}
echo "done!\n";


$functions = ['substr_startswith', 'preg_match_startswith', 'substr_compare_startswith', 'strpos_startswith', 'strncmp_startswith', 'strncmp_startswith2'];
$results = [];

foreach($functions as $func) {
    $start = microtime(true);
    foreach($test_cases as $tc) {
        $func(...$tc);
    }
    $results[$func] = (microtime(true) - $start) * 1000;
}

asort($results);

foreach($results as $func => $time) {
    echo "$func: " . number_format($time, 1) . " ms\n";
}

Ergebnisse (PHP 7.0.9)

(Am schnellsten bis am langsamsten sortiert)

strncmp_startswith2: 40.2 ms
strncmp_startswith: 42.9 ms
substr_compare_startswith: 44.5 ms
substr_startswith: 48.4 ms
strpos_startswith: 138.7 ms
preg_match_startswith: 13,152.4 ms

Ergebnisse (PHP 5.3.29)

(Am schnellsten bis am langsamsten sortiert)

strncmp_startswith2: 477.9 ms
strpos_startswith: 522.1 ms
strncmp_startswith: 617.1 ms
substr_compare_startswith: 706.7 ms
substr_startswith: 756.8 ms
preg_match_startswith: 10,200.0 ms

Starts mit_benchmark.php

mpen
quelle
3
Wenn die Zeichenfolgen nicht leer sind, wie in Ihren Tests, ist dies tatsächlich irgendwie (20-30%) schneller: function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;}Ich habe unten eine Antwort hinzugefügt.
FrancescoMM
3
@Jronny Weil 110 weniger als 133 ist ... ??
mpen
2
Verdammt, ich weiß nicht, was mir damals in den Sinn kam. Prolly der Schlafmangel.
Jronny
1
@mpen, ich habe den Elefanten überhaupt nicht bemerkt :(
Visman
1
Diese Tests sind nicht gut, um die Leistung zu testen. Was Sie tun, ist die Verwendung einer zufälligen Zeichenfolge als Nadel. In 99,99% der Fälle gibt es KEINE Übereinstimmung. Die meisten Funktionen werden nach dem Abgleichen des ersten Bytes beendet. Was ist mit Fällen, in denen eine Übereinstimmung gefunden wird? Welche Funktion benötigt am wenigsten Zeit, um ein erfolgreiches Spiel abzuschließen? Was ist mit Fällen, in denen 99% der Nadel übereinstimmen, aber nicht die letzten paar Bytes? Welche Funktion benötigt am wenigsten Zeit, um keine Übereinstimmung zu erzielen?
Salman A
137

So weit Alle Antworten Lasten unnötiger Arbeit zu tun scheinen, strlen calculations, string allocations (substr)usw. Das 'strpos'und 'stripos'Funktionen geben den Index des ersten Auftretens $needlein $haystack:

function startsWith($haystack,$needle,$case=true)
{
    if ($case)
        return strpos($haystack, $needle, 0) === 0;

    return stripos($haystack, $needle, 0) === 0;
}

function endsWith($haystack,$needle,$case=true)
{
    $expectedPosition = strlen($haystack) - strlen($needle);

    if ($case)
        return strrpos($haystack, $needle, 0) === $expectedPosition;

    return strripos($haystack, $needle, 0) === $expectedPosition;
}
Sander Rijken
quelle
2
endsWith()Funktion hat einen Fehler. Seine erste Zeile sollte (ohne -1) sein: $expectedPosition = strlen($haystack) - strlen($needle);
Enrico Detoma
6
Das strlen () Ding ist nicht unnötig. Falls die Zeichenfolge nicht mit der angegebenen Nadel beginnt, scannt Ihr Code unnötigerweise den gesamten Heuhaufen.
AppleGrew
5
@ Mark ja, nur den Anfang zu überprüfen ist viel schneller, besonders wenn Sie so etwas wie MIME-Typen überprüfen (oder an einem anderen Ort, an dem die Zeichenfolge zwangsläufig groß ist)
chacham15
2
@mark Ich habe einige Benchmarks mit 1000 Char Heuhaufen und 10 oder 800 Char Nadel gemacht und Strpos war 30% schneller. Machen Sie Ihre Benchmarks, bevor Sie feststellen, dass etwas schneller ist oder nicht ...
wdev
7
Sie sollten unbedingt in Betracht ziehen, die Nadel so zu zitieren, als strpos($haystack, "$needle", 0)ob es eine Chance gibt, dass es sich nicht bereits um eine Zeichenfolge handelt (z. B. wenn sie von stammt json_decode()). Andernfalls kann das [ungerade] Standardverhalten von strpos()zu unerwarteten Ergebnissen führen: " Wenn die Nadel keine Zeichenfolge ist, wird sie in eine Ganzzahl konvertiert und als Ordnungswert eines Zeichens angewendet. "
quietmint
46
function startsWith($haystack, $needle, $case = true) {
    if ($case) {
        return (strcmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
    }
    return (strcasecmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
}

function endsWith($haystack, $needle, $case = true) {
    if ($case) {
        return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
    }
    return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
}

Gutschrift an :

Überprüfen Sie, ob eine Zeichenfolge mit einer anderen Zeichenfolge endet

Überprüfen Sie, ob eine Zeichenfolge mit einer anderen Zeichenfolge beginnt

KdgDev
quelle
1
strtolower ist nicht der beste Weg, um Funktionen ohne Berücksichtigung der Groß- und Kleinschreibung zu verwenden. In einigen Regionen ist das Gehäuse komplexer als nur das obere und untere.
Sander Rijken
8
Ich sehe Beschwerden und keine Lösung ... Wenn Sie sagen wollen, dass es schlecht ist, sollten Sie ein Beispiel geben, wie es auch sein sollte.
KdgDev
2
@WebDevHobo: Deshalb habe ich einen Tag vor Ihrem Kommentar selbst eine Antwort hinzugefügt. Für Ihren Code war strcasecmp in der Tat das Richtige.
Sander Rijken
29

Der Regex funktioniert oben, aber mit den anderen oben ebenfalls vorgeschlagenen Verbesserungen:

 function startsWith($needle, $haystack) {
     return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
 }

 function endsWith($needle, $haystack) {
     return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
 }
Tridian
quelle
2
in PHP für String-Operationen ist die Reihenfolge der Parameter $ Heuhaufen, $ Nadel. Diese Funktionen sind rückwärts und wirken wie Array-Funktionen, bei denen die Reihenfolge tatsächlich $ Nadel, $ Heuhaufen ist.
Andy
29

Diese Frage hat bereits viele Antworten, aber in einigen Fällen können Sie sich mit etwas Einfacherem als allen zufrieden geben. Wenn die gesuchte Zeichenfolge bekannt ist (fest codiert), können Sie reguläre Ausdrücke ohne Anführungszeichen usw. verwenden.

Überprüfen Sie, ob eine Zeichenfolge mit 'ABC' beginnt:

preg_match('/^ABC/', $myString); // "^" here means beginning of string

endet mit 'ABC':

preg_match('/ABC$/', $myString); // "$" here means end of string

In meinem einfachen Fall wollte ich überprüfen, ob eine Zeichenfolge mit einem Schrägstrich endet:

preg_match('#/$#', $myPath);   // Use "#" as delimiter instead of escaping slash

Der Vorteil: Da es sehr kurz und einfach ist, müssen Sie keine Funktion definieren (z endsWith() ) wie oben gezeigt definieren.

Aber nochmal - dies ist nicht für jeden Fall eine Lösung, nur für diesen sehr spezifischen.

noamtm
quelle
Sie müssen die Zeichenfolge nicht hart codieren. Der Regex kann dynamisch sein.
Ryan
2
@self true, aber wenn die Zeichenfolge nicht fest codiert ist, müssen Sie sie maskieren. Derzeit gibt es 2 Antworten auf diese Frage, die dies tun. Das ist einfach, aber es kompliziert den Code nur ein bisschen. Mein Punkt war also, dass Sie es in sehr einfachen Fällen, in denen Hardcodierung möglich ist, einfach halten können.
Noamtm
1
Sie müssen sich auch nicht dem Schrägstrich entziehen, sondern können den regulären Ausdruck in ein anderes Zeichen einschließen, z. B. @damit der Schrägstrich ( /) nicht maskiert werden muss. Siehe Beispiel 3 hier: php.net/manual/en/function.preg-match.php .
CJBarth
Danke @cjbarth. Meine Antwort wurde entsprechend geändert. Übrigens ist "#" das Beispiel in php.net/manual/en/regexp.reference.delimiters.php, wenn es sich um einen Schrägstrich handelt.
Noamtm
23

Wenn Geschwindigkeit für Sie wichtig ist, versuchen Sie dies (ich glaube, es ist die schnellste Methode)

Funktioniert nur für Strings und wenn $ haystack nur 1 Zeichen ist

function startsWithChar($needle, $haystack)
{
   return ($needle[0] === $haystack);
}

function endsWithChar($needle, $haystack)
{
   return ($needle[strlen($needle) - 1] === $haystack);
}

$str='|apples}';
echo startsWithChar($str,'|'); //Returns true
echo endsWithChar($str,'}'); //Returns true
echo startsWithChar($str,'='); //Returns false
echo endsWithChar($str,'#'); //Returns false
Lepe
quelle
1
Dies ist wahrscheinlich die effizienteste Antwort, da keine Funktion als zusätzliche, nur übliche Zeichenfolge verwendet wird ...
Es sollte wahrscheinlich prüfen, ob die Zeichenfolge mindestens ein Zeichen hat und die beiden Parameter vertauscht sind
a1an
1
Kreativ. Nadeln, die Heuhaufen enthalten. Übrigens gibt es ein hässliches Abnehmen mit : endsWithChar('','x'), aber das Ergebnis ist korrekt
Tino
18

Hier sind zwei Funktionen, die keine temporäre Zeichenfolge einführen. Dies kann nützlich sein, wenn die Nadeln sehr groß sind:

function startsWith($haystack, $needle)
{
    return strncmp($haystack, $needle, strlen($needle)) === 0;
}

function endsWith($haystack, $needle)
{
    return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
Jack
quelle
2
+1 Funktioniert seit PHP5.1 und IMHO beste Antwort. Aber endsWidthsollte tun return $needle==='' || substr_compare(... so funktioniert es wie erwartet, für -strlen($needle)===0die, ohne das Update, endsWith('a','')zurückkehrtfalse
Tino
@Tino Danke ... Ich denke, das ist ein Fehler substr_compare(), also habe ich eine PR hinzugefügt , um das zu beheben :)
Ja͢ck
3
Der Aufruf endsWith('', 'foo')löst eine Warnung aus: "substr_compare (): Die Startposition darf die anfängliche Zeichenfolgenlänge nicht überschreiten." Vielleicht ist das ein weiterer Fehler substr_compare(), aber um ihn zu vermeiden, benötigen Sie eine || (strlen($needle) <= strlen($haystack) && substr_compare() === 0);
Vorabprüfung
@gx_ Keine Notwendigkeit, mit mehr Code zu verlangsamen. Verwenden Sie einfach return $needle === '' || @substr_compare(.., um diese Warnung zu unterdrücken.
Tino
17

Schnellste EndenWith () Lösung:

# Checks if a string ends in a string
function endsWith($haystack, $needle) {
    return substr($haystack,-strlen($needle))===$needle;
}

Benchmark:

# This answer
function endsWith($haystack, $needle) {
    return substr($haystack,-strlen($needle))===$needle;
}

# Accepted answer
function endsWith2($haystack, $needle) {
    $length = strlen($needle);

    return $length === 0 ||
    (substr($haystack, -$length) === $needle);
}

# Second most-voted answer
function endsWith3($haystack, $needle) {
    // search forward starting from end minus needle length characters
    if ($needle === '') {
        return true;
    }
    $diff = \strlen($haystack) - \strlen($needle);
    return $diff >= 0 && strpos($haystack, $needle, $diff) !== false;
}

# Regex answer
function endsWith4($haystack, $needle) {
    return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}

function timedebug() {
    $test = 10000000;

    $time1 = microtime(true);
    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith('TestShortcode', 'Shortcode');
    }
    $time2 = microtime(true);
    $result1 = $time2 - $time1;

    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith2('TestShortcode', 'Shortcode');
    }
    $time3 = microtime(true);
    $result2 = $time3 - $time2;

    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith3('TestShortcode', 'Shortcode');
    }
    $time4 = microtime(true);
    $result3 = $time4 - $time3;

    for ($i=0; $i < $test; $i++) {
        $tmp = endsWith4('TestShortcode', 'Shortcode');
    }
    $time5 = microtime(true);
    $result4 = $time5 - $time4;

    echo $test.'x endsWith: '.$result1.' seconds # This answer<br>';
    echo $test.'x endsWith2: '.$result4.' seconds # Accepted answer<br>';
    echo $test.'x endsWith3: '.$result2.' seconds # Second most voted answer<br>';
    echo $test.'x endsWith4: '.$result3.' seconds # Regex answer<br>';
    exit;
}
timedebug();

Benchmark-Ergebnisse:

10000000x endsWith: 1.5760900974274 seconds # This answer
10000000x endsWith2: 3.7102129459381 seconds # Accepted answer
10000000x endsWith3: 1.8731069564819 seconds # Second most voted answer
10000000x endsWith4: 2.1521229743958 seconds # Regex answer
Lucas Bustamante
quelle
3
+1, um sich Zeit zu nehmen, um verschiedene Lösungen zu vergleichen und sie tatsächlich zu bewerten! Sie sollten auch erwähnen, welche Version von PHP Sie verwendet haben, da Optimierungen vorgenommen werden, wenn sich die Sprache weiterentwickelt! Ich habe dramatische Verbesserungen bei den String-Vergleichsfunktionen von einer PHP-Version zur anderen gesehen :)
Christophe Deliens
1
Echo @ChristopheDeliens und seine Anfrage, die PHP-Version bereitzustellen. Ich habe Ihren Test am 7.3.2 durchgeführt und ähnliche Ergebnisse FWIW erhalten.
Jeff
16

Mir ist klar, dass dies abgeschlossen ist, aber Sie können sich strncmp ansehen, da Sie so die Länge der Zeichenfolge zum Vergleichen angeben können.

function startsWith($haystack, $needle, $case=true) {
    if ($case)
        return strncasecmp($haystack, $needle, strlen($needle)) == 0;
    else
        return strncmp($haystack, $needle, strlen($needle)) == 0;
}    
James Black
quelle
Wie würden Sie damit enden?
Mpen
@Mark - Sie können sich die akzeptierte Antwort ansehen, aber ich bevorzuge die Verwendung von strncmp, hauptsächlich weil ich denke, dass es sicherer ist.
James Black
Ich meine mit strncmp speziell. Sie können keinen Versatz angeben. Das würde bedeuten, dass Ihre EndsWith-Funktion eine völlig andere Methode verwenden müsste.
Mpen
@Mark - Für EndsWith würde ich nur strrpos ( php.net/manual/en/function.strrpos.php ) verwenden, aber im Allgemeinen ist strcmp strncmp wahrscheinlich immer eine sicherere Option, wenn Sie strcmp verwenden.
James Black
11

Sie können strposund verwendenstrrpos

$bStartsWith = strpos($sHaystack, $sNeedle) == 0;
$bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle);
Lex
quelle
1
Sollten Sie triple equals hier verwendet werden , strpos($sHaystack, $sNeedle) == 0wie dies strpos($sHaystack, $sNeedle) === 0? Ich sehe einen Fehler, wenn false == 0ausgewertet wird true.
Kalyan
11

Hier ist eine Multi-Byte-sichere Version der akzeptierten Antwort. Sie funktioniert gut für UTF-8-Zeichenfolgen:

function startsWith($haystack, $needle)
{
    $length = mb_strlen($needle, 'UTF-8');
    return (mb_substr($haystack, 0, $length, 'UTF-8') === $needle);
}

function endsWith($haystack, $needle)
{
    $length = mb_strlen($needle, 'UTF-8');
    return $length === 0 ||
        (mb_substr($haystack, -$length, $length, 'UTF-8') === $needle);
}
Vahid Amiri
quelle
2
Ich bin mir ziemlich sicher, dass dies nur eine Verschwendung von CPU ist. Alles, was Sie für StarstWith und EndsWith überprüfen müssen, ist nur zu überprüfen, ob die Bytes übereinstimmen, und genau das tut die akzeptierte Antwort. Diese 1 verschwendet Zeit bei der Berechnung der Anzahl der utf8-Zeichen der Nadel und der Position des n-ten utf8-Zeichens des Heuhaufens. Ich denke, ohne 100% sicher zu sein, ist dies nur eine Verschwendung von CPU. Können Sie einen tatsächlichen Testfall erstellen, bei dem die akzeptierte Antwort fehlschlägt, und dies nicht?
Hanshenrik
2
@hanshenrik - es kann übrigens passieren, in dem sehr seltenen Fall, wenn Sie nach einer Zeichenfolge suchen, die dieselben Bytes wie eine UTF8 enthält, aber die Hälfte des letzten Zeichens fehlt. Sie haben den Unicode C5 91 (Buchstabe "ő") und suchen nach C5 (Buchstabe "Å"), der Ihnen keine Übereinstimmung geben sollte. Auf der anderen Seite, sicher, warum sollten Sie einen utf-Heuhaufen nach einer Nicht-utf-Nadel durchsuchen ... Aber für kugelsichere Überprüfungen muss dies als eine Möglichkeit angesehen werden.
dkellner
Darin startsWithsollte sein$length = mb_strlen($needle, 'UTF-8');
Thomas Kekeisen
2
@ ThomasKekeisen Danke, behoben.
Vahid Amiri
8

Kurze und leicht verständliche Einzeiler ohne reguläre Ausdrücke.

startWith () ist unkompliziert.

function startsWith($haystack, $needle) {
   return (strpos($haystack, $needle) === 0);
}

EndenWith () verwendet das etwas ausgefallene und langsame strrev ():

function endsWith($haystack, $needle) {
   return (strpos(strrev($haystack), strrev($needle)) === 0);
}
Dan
quelle
@FrancescoMM: strpos ist nicht das "richtige Werkzeug" ... Warum? Was sind dann die "richtigen Werkzeuge"? EDIT: Ich habe Ihre Antwort unten gelesen. Ich dachte, Programmieren ist wie eine Erfindung mit den Ressourcen, die Sie haben. Es gibt also kein Richtig oder Falsch. Nur funktionieren oder nicht funktionieren. Leistung ist zweitrangig.
Fr0zenFyr
"weil es ein Werkzeug zum Suchen ist, nicht zum Vergleichen?" Cit. Aristoteles
FrancescoMM
7

Wenn Sie sich auf startwith konzentrieren und sicher sind, dass die Zeichenfolgen nicht leer sind, beschleunigt das Hinzufügen eines Tests für das erste Zeichen vor dem Vergleich, die Zeichenfolge usw. die Dinge ein wenig:

function startswith5b($haystack, $needle) {
    return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
}

Es ist irgendwie (20% -30%) schneller. Das Hinzufügen eines weiteren Char-Tests wie $ haystack {1} === $ Needle {1} scheint die Dinge nicht wesentlich zu beschleunigen, kann sogar langsamer werden.

===scheint schneller als == Bedingter Operator (a)?b:cscheint schneller alsif(a) b; else c;


Für diejenigen, die fragen: "Warum nicht Strpos verwenden?" andere Lösungen als "unnötige Arbeit" bezeichnen


strpos ist schnell, aber nicht das richtige Werkzeug für diesen Job.

Zum Verständnis hier eine kleine Simulation als Beispiel:

Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c

Was macht der Computer "drinnen"?

    With strccmp, etc...

    is a===b? NO
    return false



    With strpos

    is a===b? NO -- iterating in haysack
    is a===c? NO
    is a===d? NO
    ....
    is a===g? NO
    is a===g? NO
    is a===a? YES
    is 1===1? YES -- iterating in needle
    is 2===3? YES
    is 4===4? YES
    ....
    is 8===8? YES
    is c===x? NO: oh God,
    is a===1? NO -- iterating in haysack again
    is a===2? NO
    is a===3? NO
    is a===4? NO
    ....
    is a===x? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    ...
    ... may many times...
    ...
    is a===b? NO
    is a===a? YES -- iterating in needle again
    is 1===1? YES
    is 2===3? YES
    is 4===4? YES
    is 8===8? YES
    is c===c? YES YES YES I have found the same string! yay!
    was it at position 0? NOPE
    What you mean NO? So the string I found is useless? YEs.
    Damn.
    return false

Angenommen, strlen iteriert nicht die gesamte Zeichenfolge (aber selbst in diesem Fall) ist dies überhaupt nicht praktisch.

FrancescoMM
quelle
Es gibt nur eine Beschleunigung, wenn die ersten Zeichen unterschiedlich sind.
Ja͢ck
2
@ Jack ja, natürlich ist die Idee, dass dies statistisch gesehen geschieht, so dass die Beschleunigung im Allgemeinen 20% -30% über den gesamten Testsatz beträgt (einschließlich der Fälle, in denen dies nicht anders ist). Sie gewinnen viel, wenn sie unterschiedlich sind, und verlieren sehr wenig, wenn sie nicht sind. Im Durchschnitt gewinnen Sie diese 30% (variiert je nach Satz, aber meistens gewinnen Sie Geschwindigkeit bei großen Tests)
FrancescoMM
"aber es ist nicht das richtige Werkzeug für diesen Job" ... Irgendwelche Zitate?
Fr0zenFyr
1
WTF. Ich habe alle Prozesse aufgelistet, unter denen ich mehr zitieren soll. Würden Sie eine Funktion verwenden, die bis zum Ende einer Zeichenfolge sucht, um Ihnen mitzuteilen, dass das Faustzeichen kein 'a' ist? Ist es wen interessiert? Es ist nicht das richtige Werkzeug, weil es ein Werkzeug zum Suchen und nicht zum Vergleichen ist. Es ist nicht nötig, Aristoteles zu zitieren, um das Offensichtliche zu sagen!
FrancescoMM
6

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

$content = "The main string to search";
$search = "T";
//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';
Srinivasan.S
quelle
6

Normalerweise gehe ich heutzutage mit einer Bibliothek wie underscore-php .

require_once("vendor/autoload.php"); //use if needed
use Underscore\Types\String; 

$str = "there is a string";
echo( String::startsWith($str, 'the') ); // 1
echo( String::endsWith($str, 'ring')); // 1   

Die Bibliothek ist voll von anderen praktischen Funktionen.

Yuvilio
quelle
6

Die Antwort von mpen ist unglaublich gründlich, aber leider hat der bereitgestellte Benchmark eine sehr wichtige und nachteilige Kontrolle.

Da jedes Byte in Nadeln und Heuhaufen völlig zufällig ist, beträgt die Wahrscheinlichkeit, dass sich ein Nadel-Heuhaufen-Paar im ersten Byte unterscheidet, 99,609375%, was bedeutet, dass sich im Durchschnitt etwa 99609 der 100000 Paare im ersten Byte unterscheiden . Mit anderen Worten, der Benchmark ist stark auf startswithImplementierungen ausgerichtet, die das erste Byte explizit prüfen, wie zstrncmp_startswith2 .

Wenn die Testgenerierungsschleife stattdessen wie folgt implementiert wird:

echo 'generating tests';
for($i = 0; $i < 100000; ++$i) {
    if($i % 2500 === 0) echo '.';

    $haystack_length = random_int(1, 7000);
    $haystack = random_bytes($haystack_length);

    $needle_length = random_int(1, 3000);
    $overlap_length = min(random_int(0, $needle_length), $haystack_length);
    $needle = ($needle_length > $overlap_length) ?
        substr($haystack, 0, $overlap_length) . random_bytes($needle_length - $overlap_length) :
        substr($haystack, 0, $needle_length);

    $test_cases[] = [$haystack, $needle];
}
echo " done!<br />";

Die Benchmark-Ergebnisse erzählen eine etwas andere Geschichte:

strncmp_startswith: 223.0 ms
substr_startswith: 228.0 ms
substr_compare_startswith: 238.0 ms
strncmp_startswith2: 253.0 ms
strpos_startswith: 349.0 ms
preg_match_startswith: 20,828.7 ms

Natürlich ist dieser Benchmark möglicherweise noch nicht vollkommen unvoreingenommen, aber er testet die Effizienz der Algorithmen, wenn auch teilweise passende Nadeln gegeben werden.

Veeno
quelle
5

Zusamenfassend:

function startsWith($str, $needle){
   return substr($str, 0, strlen($needle)) === $needle;
}

function endsWith($str, $needle){
   $length = strlen($needle);
   return !$length || substr($str, - $length) === $needle;
}
Vincent Pazeller
quelle
5

Nur eine Empfehlung:

function startsWith($haystack,$needle) {
    if($needle==="") return true;
    if($haystack[0]<>$needle[0]) return false; // ------------------------- speed boost!
    return (0===substr_compare($haystack,$needle,0,strlen($needle)));
}

Diese zusätzliche Zeile, in der das erste Zeichen der Zeichenfolgen verglichen wird, kann dazu führen, dass der falsche Fall sofort zurückkehrt , wodurch viele Ihrer Vergleiche viel schneller werden (7x schneller, wenn ich gemessen habe). Im wahren Fall zahlen Sie für diese einzelne Leitung praktisch keinen Preis für die Leistung, daher denke ich, dass es sich lohnt, sie einzubeziehen. (In der Praxis schlagen die meisten Vergleiche fehl, wenn Sie viele Zeichenfolgen auf einen bestimmten Startblock testen, da Sie in einem typischen Fall nach etwas suchen.)

dkellner
quelle
2
Fehler in Ihrem Code: startsWith("123", "0")gibttrue
Tino
Ja, schlecht! $ Überprüfung ist passiert. Es tut uns leid! (
Ich
4

Die substrFunktion kann falsein vielen Sonderfällen zurückgegeben werden. Hier ist meine Version, die sich mit folgenden Problemen befasst:

function startsWith( $haystack, $needle ){
  return $needle === ''.substr( $haystack, 0, strlen( $needle )); // substr's false => empty string
}

function endsWith( $haystack, $needle ){
  $len = strlen( $needle );
  return $needle === ''.substr( $haystack, -$len, $len ); // ! len=0
}

Tests ( truebedeutet gut):

var_dump( startsWith('',''));
var_dump( startsWith('1',''));
var_dump(!startsWith('','1'));
var_dump( startsWith('1','1'));
var_dump( startsWith('1234','12'));
var_dump(!startsWith('1234','34'));
var_dump(!startsWith('12','1234'));
var_dump(!startsWith('34','1234'));
var_dump('---');
var_dump( endsWith('',''));
var_dump( endsWith('1',''));
var_dump(!endsWith('','1'));
var_dump( endsWith('1','1'));
var_dump(!endsWith('1234','12'));
var_dump( endsWith('1234','34'));
var_dump(!endsWith('12','1234'));
var_dump(!endsWith('34','1234'));

Auch die substr_compareFunktion ist einen Blick wert. http://www.php.net/manual/en/function.substr-compare.php

biziclop
quelle
4

Dies kann funktionieren

function startsWith($haystack, $needle) {
     return substr($haystack, 0, strlen($needle)) == $needle;
}

Quelle: https://stackoverflow.com/a/4419658

user507410
quelle
4

Ich würde es so machen

     function startWith($haystack,$needle){
              if(substr($haystack,0, strlen($needle))===$needle)
              return true;
        }

  function endWith($haystack,$needle){
              if(substr($haystack, -strlen($needle))===$needle)
              return true;
        }
Jelle Keiser
quelle
Vergessen, false zurückzugeben, wenn es nicht übereinstimmt. Errgo falsch, da der Rückgabewert einer Funktion nicht "angenommen" werden sollte, aber ich weiß, wonach Sie suchen, zumindest im Vergleich zu anderen Antworten.
Spoo
3

Basierend auf der Antwort von James Black ist hier das Ende mit der Version:

function startsWith($haystack, $needle, $case=true) {
    if ($case)
        return strncmp($haystack, $needle, strlen($needle)) == 0;
    else
        return strncasecmp($haystack, $needle, strlen($needle)) == 0;
}

function endsWith($haystack, $needle, $case=true) {
     return startsWith(strrev($haystack),strrev($needle),$case);

}

Hinweis: Ich habe den if-else-Teil gegen James Blacks Funktion "DoesWith" ausgetauscht, da strncasecmp die Version von strncmp ist, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird.

Bobo
quelle
2
Beachten Sie, dass das strrev()ist kreativ , aber sehr teuer, vor allem wenn man Saiten mitreden ... 100Kb.
Alexis Wilke
Verwenden Sie ===statt ==, um sicher zu sein. 0ist gleichbedeutend mit vielen Dingen in PHP.
Nawfal
3

Warum nicht das Folgende?

//How to check if a string begins with another string
$haystack = "valuehaystack";
$needle = "value";
if (strpos($haystack, $needle) === 0){
    echo "Found " . $needle . " at the beginning of " . $haystack . "!";
}

Ausgabe:

Wert zu Beginn des Valueehaystacks gefunden!

Beachten Sie, strposdass false zurückgegeben wird, wenn die Nadel nicht im Heuhaufen gefunden wurde, und 0 zurückgegeben wird, wenn und nur wenn die Nadel bei Index 0 gefunden wurde (AKA am Anfang).

Und hier endet mit:

$haystack = "valuehaystack";
$needle = "haystack";

//If index of the needle plus the length of the needle is the same length as the entire haystack.
if (strpos($haystack, $needle) + strlen($needle) === strlen($haystack)){
    echo "Found " . $needle . " at the end of " . $haystack . "!";
}

In diesem Szenario ist keine Funktion startWith () as erforderlich

(strpos($stringToSearch, $doesItStartWithThis) === 0)

wird wahr oder falsch genau zurückgeben.

Es scheint seltsam, dass es so einfach ist, wenn all die wilden Funktionen hier weit verbreitet sind.

Kade Hafen
quelle
3
Es scheint seltsam, dass Sie, wenn Sie nach "xy" in der Zeichenfolge "abcdefghijklmxyz" suchen, anstatt nur "x" mit "a" zu vergleichen und FALSE zurückzugeben, jedes Zeichen von "a" bis "m" suchen und dann "xy" finden. innerhalb der Zeichenfolge, und schließlich geben Sie FALSE zurück, weil die Position nicht Null ist! Dies ist, was Sie tun, und es ist seltsam und wilder als jede andere zügellose Funktion hier.
FrancescoMM
Die Einfachheit liegt in der Eingabe, nicht in der Logik.
Kade Hafen
Es ist nicht so sehr die Logik, sondern die mögliche Optimierung, auf die Francsco hingewiesen hat. Die Verwendung strpos()ist langsam, außer wenn sie übereinstimmt. strncmp()wäre in diesem Fall viel besser.
Alexis Wilke
Wenn Sie solche Funktionen auf niedriger Ebene ausführen, möchten Sie normalerweise die am besten für die Geschwindigkeit optimierte Lösung wählen, egal wie komplex diese ist, da sie millionenfach aufgerufen wird. Jede Mikrosekunde, die Sie hier gewinnen oder verlieren, wird einen sehr realen Unterschied machen. Also besser die Hölle raus (und dann die Komplexität vergessen, jetzt wo du die Funktion hast), anstatt nach dem Aussehen zu suchen und später schrecklich viel Zeit zu verlieren, wenn du nicht einmal weißt, was schief gelaufen ist. Stellen Sie sich vor, Sie überprüfen eine 2-GB-Zeichenfolge, die nicht übereinstimmt.
dkellner
3

Viele der vorherigen Antworten werden genauso gut funktionieren. Dies ist jedoch möglicherweise so kurz, wie Sie es schaffen und es tun lassen können, was Sie wollen. Sie geben nur an, dass Sie möchten, dass es "true" zurückgibt. Daher habe ich Lösungen eingefügt, die boolesches true / false und textuelles true / false zurückgeben.

// boolean true/false
function startsWith($haystack, $needle)
{
    return strpos($haystack, $needle) === 0 ? 1 : 0;
}

function endsWith($haystack, $needle)
{
    return stripos($haystack, $needle) === 0 ? 1 : 0;
}


// textual true/false
function startsWith($haystack, $needle)
{
    return strpos($haystack, $needle) === 0 ? 'true' : 'false';
}

function endsWith($haystack, $needle)
{
    return stripos($haystack, $needle) === 0 ? 'true' : 'false';
}
Wynshaft
quelle
Wahr. Peter bat jedoch um eine Funktion, die mit Zeichenketten funktionieren würde. Trotzdem habe ich meine Antwort aktualisiert, um Sie zu beschwichtigen.
Wynshaft
Nach der Bearbeitung ist Ihre Lösung nun völlig veraltet. Es gibt 'true'und 'false'als Zeichenfolgen zurück, die beide trueim booleschen Sinne sind. Es ist ein gutes Muster für so etwas wie underhanded.xcott.com ;)
Tino
Nun, Peter hat nur gesagt, er wollte, dass es "wahr" zurückgibt. Also dachte ich mir, ich würde zurückgeben, wonach er gefragt hat. Ich habe beide Versionen hinzugefügt, nur für den Fall, dass er das nicht wollte.
Wynshaft
2

Sie können auch reguläre Ausdrücke verwenden:

function endsWith($haystack, $needle, $case=true) {
  return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
Freeman
quelle
3
$ Nadel sollte mit entkommen werden preg_quote($needle, '/').
Timo Tijhof
2

No-Copy und No-Intern-Loop:

function startsWith(string $string, string $start): bool
{
    return strrpos($string, $start, - strlen($string)) !== false;
}

function endsWith(string $string, string $end): bool
{
    return ($offset = strlen($string) - strlen($end)) >= 0 
    && strpos($string, $end, $offset) !== false;
}
Mazatwork
quelle
Dies sollte viel schneller sein als die Implementierung von MrHus! Ich könnte es
messen
1

Hier ist eine effiziente Lösung für PHP 4. Sie könnten schnellere Ergebnisse erzielen, wenn Sie PHP 5 substr_compareanstelle von verwenden strcasecmp(substr(...)).

function stringBeginsWith($haystack, $beginning, $caseInsensitivity = false)
{
    if ($caseInsensitivity)
        return strncasecmp($haystack, $beginning, strlen($beginning)) === 0;
    else
        return strncmp($haystack, $beginning, strlen($beginning)) === 0;
}

function stringEndsWith($haystack, $ending, $caseInsensitivity = false)
{
    if ($caseInsensitivity)
        return strcasecmp(substr($haystack, strlen($haystack) - strlen($ending)), $haystack) === 0;
    else
        return strpos($haystack, $ending, strlen($haystack) - strlen($ending)) !== false;
}
Patrick Smith
quelle
0

Hierfür können Sie die Funktion fnmatch verwenden.

// Starts with.
fnmatch('prefix*', $haystack);
// Ends with.
fnmatch('*suffix', $haystack);
ya.teck
quelle
Warnung, nicht binär sicher und nicht einmal sicher gegen Nadeln mit Platzhaltern = /
hanshenrik