2009-03-06 13 views
105

La forma estándar de PHP para probar si una cadena $str termina con una subcadena $test es:¿Cuál es la prueba más eficiente de si una cadena PHP termina con otra cadena?

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

¿Es esta la forma más rápida?

+2

similares: http://stackoverflow.com/questions/834303/php-startswith- and-endswith-functions – trante

+0

Puede encontrar ['s ($ str) -> endsWith ($ test)'] (https://github.com/delight-im/PHP-Str/blob/8fd0c608d5496d43adaa899642c1cce047e076dc/src/Str. php # L117) o ['s ($ str) -> endsWithIgnoreCase ($ test)'] (https://github.com/delight-im/PHP-Str/blob/8fd0c608d5496d43adaa899642c1cce047e076dc/src/Str.php#L131) útil, como se encuentra en [esta biblioteca independiente] (https://github.com/delight-im/PHP-Str). – caw

Respuesta

132

Lo que Assaf dijo es correcto. Hay una función incorporada en PHP para hacer exactamente eso.

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

Si $test es más largo que $str PHP dará una advertencia, por lo que necesita para comprobar que la primera.

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

Agradable. Parece que comparar en el lugar sería más rápido que substr(), como señaló Assaf. –

+2

La respuesta de mcrumley es genial, pero debería usar '===' en lugar de '=='. '===' es más estricto y generalmente hace lo que quieres, mientras que '==' puede llevar a sorpresas desagradables. El tercer fragmento de código de mcrumley es correcto, pero los primeros dos no lo son. substr_compare() devuelve falso en algunos casos de error. En PHP, falso == 0, por lo que los fragmentos de código indicarán que se ha encontrado la cadena. Con ===, esto no sucede. –

+0

Me encontré con un error hoy que romperá la solución que ha dado desde PHP 5.5.11 en adelante. https://bugs.php.net/bug.php?id=67043 – user2180613

7

Depende del tipo de eficiencia que le interese.

Su versión utiliza más memoria debido a la copia adicional del uso de substr.

Una versión alternativa puede buscar en la cadena original la última aparición de la subcadena sin hacer una copia, pero probablemente sea más lenta debido a más pruebas.

Probablemente la forma más eficiente es hacer un bucle char-by-char desde la posición -sterlen (prueba) hasta el final de la cadena y comparar. Esa es la cantidad mínima de comparaciones que puede esperar hacer y casi no se usa memoria adicional.

4

Otra forma sería la de utilizar el strrpos function:

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

Pero eso no es más rápido.

0

Estoy pensando que las funciones inversas como strrchr() te ayudarían a unir el final de la cadena más rápido.

63

Este método es un poco más pequeña de memoria-caro, pero es más rápido:

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

Esto se hace mejor cuando se sabe exactamente lo que la aguja se encuentra, por lo que puede difícil que el código invertido. Si invierte la aguja de forma programática, se vuelve más lenta que el método anterior.

+0

¡Eso es tan inteligente! –

+0

+1 por originalidad! –

+2

-1 Dudo seriamente de que esto sea más rápido, y es complicado (genial, pero por lo general no es útil). Si el pajar * no * termina con la aguja, 'stripos' repetirá la cadena completa en el peor de los casos, mientras que' substr_compare' se comparará como máximo con la longitud de la aguja. Sí, 'substr_compare' requiere calcular la longitud del pajar (y una aguja mucho más pequeña), pero este método requiere que * y * lo copie en su totalidad, y posiblemente convierta todo en minúsculas para arrancar. –

7

Aquí está una manera sencilla de comprobar si una cadena termina con otra, dando strpos un desplazamiento a la derecha, donde la cadena debe ser encontrado:

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

sencillo, y creo que esto funcionará en PHP 4.

2

espero que la respuesta a continuación puede ser eficiente y sencillo:

$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'; 
-1

Esta es PHP puro, sin llamar a la función externa s, excepto 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; 
} 
35
$endsWith = substr_compare($str, $test, -strlen($test)) === 0 

desplazamiento negativo "comienza a contar desde el final de la cadena".

+3

IMO es uno de los mejores de las soluciones proporcionadas –

+4

Debe ser la respuesta aceptada – FrancescoMM

+0

+200 si pudiera. La idea clave aquí es que usar una longitud negativa obtiene la parte final de la cadena. También puede usar substr con la longitud -ve y hacer una prueba == contra $. Las otras respuestas son pobres. – Nick

1

No sabe si esto es rápido o no, pero para una sola prueba de carácter, estos trabajos, también:

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