PHP: Wie prüft man ob ein String mit etwas beginnt oder endet?
Oft steht man vor der Anforderung feststellen zu müssen ob ein String mit einem
bestimmten Teilstring beginnt oder endet. Beispielsweise ob eine URL mit
https:// beginnt oder ein Dateiname auf .php endet.
Ab PHP Version 8
Seit PHP Version 8.0 gibt es dafür die beiden Funktionen str_starts_with und str_ends_with. Beide nehmen Rücksicht auf die Groß- und Kleinschreibung (case-sensitive):
<?php
$url = 'https://www.hostinggutscheine.de/blog/';
if (str_starts_with($url, 'https://')) {
// Die folgende Codezeile wird ausgeführt.
echo "Die URL beginnt mit 'https://'.\n";
}
if (str_ends_with($url, '/')) {
// Die folgende Codezeile wird ausgeführt.
echo "Die URL endet mit einem Schrägstrich.\n";
}
if (str_starts_with($url, 'HTTPS://')) {
// Die folgende Codezeile wird NICHT ausgeführt.
echo "Die URL beginnt mit 'HTTPS://'.\n";
}
?>
Soll die Groß- und Kleinschreibung keine Rolle spielen, überführst du beide Strings vorher in Kleinbuchstaben. Dazu verwendest du die Funktion strtolower:
<?php
if (str_starts_with(strtolower($url), 'https://')) {
// Die folgende Codezeile wird ausgeführt.
echo "Die URL beginnt mit 'https://' (unabhängig von der Schreibweise).\n";
}
?>
Ein leerer Suchstring liefert bei beiden Funktionen true. Das ist die
mathematisch saubere Antwort, denn jeder String beginnt und endet mit nichts:
str_starts_with('abc', '') => true
str_ends_with('abc', '') => true
Vor PHP Version 8
Setzt du eine ältere Version von PHP ein musst du dir die beiden Funktionen selbst schreiben. Für den Anfang eines Strings ist das unproblematisch:
<?php
function startsWith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) === $needle;
}
?>
Beim Ende lauert allerdings eine Falle. Sehr verbreitet ist diese Kurzform:
<?php
function endsWith($haystack, $needle) {
// Achtung, diese Variante ist fehlerhaft!
return substr($haystack, -strlen($needle)) === $needle;
}
?>
Ist der Suchstring leer, dann ist strlen($needle) gleich 0 und der Aufruf
lautet substr($haystack, -0). Und -0 ist in PHP schlicht 0. Damit liefert
substr() nicht den leeren String zurück, sondern den kompletten String:
substr($url, -0) => 'https://www.hostinggutscheine.de/blog/'
Die Funktion antwortet in diesem Fall also false, obwohl true richtig wäre.
Du brauchst daher eine ausdrückliche Abfrage:
<?php
function endsWith($haystack, $needle) {
$length = strlen($needle);
if ($length === 0) {
return true;
}
return substr($haystack, -$length) === $needle;
}
?>
Warum nicht strpos?
Man liest oft den Vorschlag, für den Stringanfang strpos zu verwenden:
<?php
if (strpos($haystack, $needle) === 0) {
// ...
}
?>
Das funktioniert, ist aber das falsche Werkzeug. strpos() sucht den
Teilstring im gesamten String und erst danach vergleichst du die gefundene
Position mit 0. Ob der String an Position 0 beginnt, steht aber schon nach
dem Vergleich des ersten Zeichens fest.
Ich habe das nachgemessen. Als Haystack dienen 20.000 Zeichen b gefolgt von
needle, gesucht wird 20.000 mal nach needle am Anfang:
str_starts_with : 0.000 s
strpos === 0 : 0.002 s
In absoluten Zahlen ist das wenig. Der Punkt ist ein anderer: Der Aufwand von
strpos() wächst mit der Länge des Strings, der von str_starts_with() nicht.
Bei kurzen Strings merkst du davon nichts, bei großen Dokumenten schon.
Was ist mit Umlauten?
Die beiden Funktionen vergleichen byteweise und nicht zeichenweise. Trotzdem
brauchst du keine mb_*-Varianten:
str_starts_with('Über uns', 'Ü') => true
strlen('Ü') => 2
mb_strlen('Ü') => 1
Das Ü belegt in UTF-8 zwei Bytes, das Ergebnis stimmt aber. Der Grund ist,
dass UTF-8 präfixfrei ist: Das erste Byte eines Zeichens kann niemals als
Folgebyte eines anderen Zeichens auftreten. Ein byteweiser Vergleich am Anfang
oder am Ende eines Strings kann daher nicht mitten in einem Zeichen “landen”.
Hinweis zu Netcup (Werbung)
Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).