Quel est le test le plus efficace pour savoir si une chaîne PHP se termine par une autre chaîne?

Réponses:

152

Ce qu'Assaf a dit est correct. Il existe une fonction intégrée en PHP pour faire exactement cela.

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

Si $testest plus long que $strPHP donnera un avertissement, vous devez donc vérifier cela en premier.

function endswith($string, $test) {
    $strlen = strlen($string);
    $testlen = strlen($test);
    if ($testlen > $strlen) return false;
    return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
}
mcrumley
la source
Agréable. Il semble que comparer sur place serait plus rapide que substr (), comme l'a souligné Assaf.
Jason Cohen
2
La réponse de mcrumley est cool, mais il devrait utiliser '===' au lieu de '=='. '===' est plus strict et fait généralement ce que vous voulez, tandis que '==' peut conduire à de mauvaises surprises. Le troisième extrait de code de mcrumley est correct, mais les deux premiers ne le sont pas. substr_compare () retourne false dans certains cas d'erreur. En PHP, false == 0, donc les extraits de code signalent que la chaîne a été trouvée. Avec ===, cela n'arrive pas.
jcsahnwaldt Réintègre Monica
1
J'ai rencontré un bug aujourd'hui qui cassera la solution que vous avez donnée à partir de PHP 5.5.11 et au-delà. bugs.php.net/bug.php?id=67043
user2180613
La surcharge des appels à 3 fonctions ne le rend pas plus rapide
Thanh Trung
66

Cette méthode est un peu plus chère en mémoire, mais elle est plus rapide:

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

Cela est préférable lorsque vous savez exactement ce qu'est l'aiguille, afin de pouvoir la coder en dur. Si vous inversez l'aiguille par programme, elle devient plus lente que la méthode précédente.

jscheel
la source
2
-1 Je doute sérieusement que ce soit plus rapide, et c'est délicat (cool mais généralement pas utile). Si la botte de foin ne se termine pas par l'aiguille, stripositérera toute la chaîne dans le pire des cas alors que substr_comparecomparera au plus la longueur de l'aiguille. Oui, substr_comparenécessite de calculer la longueur de la botte de foin (et de l'aiguille beaucoup plus petite), mais cette méthode nécessite cela et de la copier dans son intégralité, et éventuellement de convertir le tout en minuscules pour démarrer.
David Harkness
approche cool mais inefficace (comme mentionné dans la réponse elle-même) dans de nombreux cas! Encore un vote positif pour être étrangement créatif et avoir démontré qu'il peut toujours y avoir plus de façons de faire la même chose que vous pourriez imaginer. À votre santé!
Fr0zenFyr
1
J'ai testé et trouve cette méthode plus rapidement que la réponse acceptée. Même si la botte de foin et l'aiguille sont inversées à la volée, c'est plus rapide.
Shumoapp
@DavidHarkness Avez-vous testé pour voir si vos doutes étaient justifiés?
Nathan
@Nathan Non, ça ne vaut pas le temps de faire des benchmarks car ça substr_compare()marche bien.
David Harkness
61
$endsWith = substr_compare( $str, $test, -strlen( $test ) ) === 0

Le décalage négatif "commence à compter à partir de la fin de la chaîne".

Alexandre Yanovets
la source
3
IMO, c'est l'un des meilleurs parmi les solutions fournies
Roman Podlinov
+200 si je pouvais. Le point clé ici est que l'utilisation d'une longueur négative obtient la partie finale de la chaîne. Vous pouvez également utiliser substr avec la longueur -ve et faire un == contre $ test. Les autres réponses sont médiocres.
Nick
11

Voici un moyen simple de vérifier si une chaîne se termine par une autre, en donnant strposun décalage à l'endroit où la chaîne doit être trouvée:

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

Simple, et je pense que cela fonctionnera en PHP 4.

Patrick Smith
la source
8

Cela dépend du type d'efficacité qui vous tient à cœur.

Votre version utilise plus de mémoire en raison de la copie supplémentaire de l'utilisation de substr.

Une version alternative pourrait rechercher dans la chaîne d'origine la dernière occurrence de la sous-chaîne sans faire de copie, mais serait probablement plus lente en raison de tests supplémentaires.

Le moyen le plus efficace est probablement de faire une boucle char-par-char de la position -sterlen (test) jusqu'à la fin de la chaîne et de comparer. C'est la quantité minimale de comparaisons que vous pouvez espérer faire et il n'y a pratiquement pas de mémoire supplémentaire utilisée.

Assaf Lavie
la source
5

Une autre façon serait d'utiliser la strrposfonction :

strrpos($str, $test) == strlen($str) - strlen($test)

Mais ce n'est pas plus rapide.

Gombo
la source
3

J'espère que la réponse ci-dessous peut être efficace et aussi simple:

$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';
Srinivasan.S
la source
2

Je ne sais pas si c'est rapide ou non, mais pour un test de caractère unique, cela fonctionne aussi:

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

moyen le plus simple de le vérifier via une expression régulière

par exemple pour vérifier si le mail fourni est gmail:

echo (preg_match("/@gmail\.com$/","[email protected]"))?'true':'false';
Biskrem Muhammad
la source
0

Je pense que les fonctions inverses comme strrchr () vous aideraient à faire correspondre la fin de la chaîne le plus rapidement.

tkotitan
la source
0

C'est du PHP pur, sans appeler de fonctions externes, à l'exception de 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;
}
Xesau
la source
0

pour une aiguille à un caractère:

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
kabantejay
la source