Funciones startsWith () y endsWith () en PHP

¿Cómo puedo escribir dos funciones que tomarían una cadena y regresarían si comienza con el carácter / cadena especificado o termina con él?

Por ejemplo:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true

preguntado el 07 de mayo de 09 a las 12:05

Ver Laravel's Clase str startsWith () y endsWith () para bien probado métodos. Casos de borde se ha encontrado, por lo que el uso generalizado de este código es una ventaja. -

Usted puede encontrar s($str)->startsWith('|') y s($str)->endsWith('}') útil, como se encuentra en esta biblioteca independiente. -

Advertencia: la mayoría de las respuestas aquí no son confiables en codificaciones de varios bytes como UTF-8. -

Siguiendo con mi comentario anterior, puede asegurarse de utilizar la última versión (a partir de hoy, 5.4). En particular, startsWith () se ha optimizado para cadenas de pajar grandes. -

PHP 8.0 introduce nuevos métodos para este trabajo str_starts_with y str_end_with: stackoverflow.com/a/64160081/7082164 -

30 Respuestas

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

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

Use esto si no desea usar una expresión regular.

Respondido 17 Jul 20, 01:07

Yo diría que endsWith ('foo', '') == false es el comportamiento correcto. Porque foo no termina con nada. 'Foo' termina con 'o', 'oo' y 'Foo'. - MrHus

EndsWith se puede escribir mucho más corto: return substr($haystack, -strlen($needle))===$needle; - Rok Kralj

@RokKralj Pero solo si $needle no está vacío. - Jack

Puedes evitar el if en conjunto pasando $length como tercer parámetro para substr: return (substr($haystack, -$length, $length);. Esto maneja el caso de $length == 0 devolviendo una cadena vacía y no la totalidad $haystack. - mxxk

@MrHus Recomendaría usar funciones seguras de múltiples bytes, por ejemplo, mb_strlen y mb_substr - 19 Gerhard 85

Puedes usar substr_compare función para comprobar inicio-con y termina-con:

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;
}

Esta debería ser una de las soluciones más rápidas en PHP 7 (secuencia de comandos de referencia). Probado contra pajares de 8 KB, agujas de varias longitudes y estuches completos, parciales y sin coincidencias. strncmp es un toque más rápido para empezar con, pero no puede marcar los finales con.

Respondido 24 Abr '19, 11:04

¡Esta respuesta llegó al Daily WTF! : D Ver thedailywtf.com/articles/… - Wim ten Brink

Tenga en cuenta que los comentarios de @DavidWallace y @FrancescoMM se aplican a una versión anterior de esta respuesta. La respuesta actual usa strrpos que (debería) fallar inmediatamente si la aguja no coincide con el comienzo del pajar. - Salman A

No lo entiendo. Residencia en php.net/manual/en/function.strrpos.php: "Si el valor es negativo, la búsqueda comenzará a partir de esa cantidad de caracteres desde el final de la cadena, buscando hacia atrás". Esto parece indicar que estamos comenzando en el carácter 0 (debido a -strlength($haystack)) y buscando hacia atrás ¿desde allí? ¿No significa eso que no estás buscando nada? Tampoco entiendo el !== false partes de esto. Supongo que esto se basa en una peculiaridad de PHP donde algunos valores son "verdaderos" y otros "falsos", pero ¿cómo funciona eso en este caso? - Welbog

@Welbog: por ejemplo pajar = xxxyyy aguja = yyy y utilizando strrpos la búsqueda comienza desde el primero x. Ahora no tenemos una coincidencia exitosa aquí (encontramos x en lugar de y) y ya no podemos retroceder (estamos al comienzo de la cadena) la búsqueda falla inmediatamente. Sobre el uso !== false -- strrpos en el ejemplo anterior devolverá 0 o falso y no otro valor. Igualmente, strpos en el ejemplo anterior puede volver $temp (la posición esperada) o falso. Yo fui con !== false por consistencia, pero podrías usar === 0 y === $temp en las funciones respectivamente. - Salman A

@spoo ya se ha establecido que strpos === 0 es una solución terrible si el pajar es grande y la aguja no existe. - Salman A

Actualizado el 23 de agosto de 2016

Las funciones clave

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;
}

Examenes

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";
}

Resultados (PHP 7.0.9)

(Ordenados de más rápido a más lento)

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

Resultados (PHP 5.3.29)

(Ordenados de más rápido a más lento)

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

startswith_benchmark.php

Respondido el 28 de junio de 17 a las 22:06

Si las cadenas no están vacías, como en sus pruebas, esto es en realidad de alguna manera (20-30%) más rápido: function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;} Agregué una respuesta a continuación. - FrancescoMM

@Jronny Porque 110 es menos que 133 ... ?? - mpen

Maldita sea, no sé qué se me pasó por la cabeza esa vez. Probablemente la falta de sueño. - Jronny

@mpen, no noté el elefante en absoluto :( - Visman

$haystack[0] arrojará un error de aviso si no lo prueba con isset. Lo mismo para las agujas. Pero si agrega pruebas, ralentizará su rendimiento: Thanh Trung

Todas las respuestas hasta ahora parecen hacer un montón de trabajo innecesario, strlen calculations, string allocations (substr), etc. El 'strpos' y 'stripos' Las funciones devuelven el índice de la primera aparición de $needle in $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;
}

Respondido 04 ago 15, 18:08

endsWith() La función tiene un error. Su primera línea debería ser (sin el -1): $expectedPosition = strlen($haystack) - strlen($needle); - Enrico Detoma

La cosa strlen () no es innecesaria. En caso de que la cadena no comience con la aguja dada, nuestro código escaneará innecesariamente todo el pajar. - AppleGrew

@Mark sí, verificar solo el comienzo es MUCHO más rápido, especialmente si está haciendo algo como verificar los tipos MIME (o cualquier otro lugar donde la cadena esté destinada a ser grande) - chacham15

@mark Hice algunos puntos de referencia con un pajar de 1000 caracteres y una aguja de 10 u 800 caracteres y strpos fue un 30% más rápido. Haz tus benchmarks antes de afirmar que algo es más rápido o no ... - wdev

Debería considerar seriamente citar la aguja como strpos($haystack, "$needle", 0) si hay cualquier posibilidad de que no sea ya una cadena (p. ej., si viene de json_decode()). De lo contrario, el [extraño] comportamiento predeterminado de strpos() puede causar resultados inesperados: "Si la aguja no es una cadena, se convierte en un número entero y se aplica como el valor ordinal de un carácter."- tranquila

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);
}

Crédito a:

Comprueba si una cuerda termina con otra cuerda

Compruebe si una cadena comienza con otra cadena

Respondido 01 ago 13, 19:08

strtolower no es la mejor manera de hacer funciones que no distingan entre mayúsculas y minúsculas. En algunos lugares, la carcasa es más compleja que solo superior e inferior. - Sander Rijken

Veo quejas y ninguna solución ... Si vas a decir que es malo, entonces deberías dar un ejemplo de cómo debería ser. - KdgDev

@WebDevHobo: es por eso que yo mismo agregué una respuesta un día antes de tu comentario. Para su código, strcasecmp fue lo correcto. - Sander Rijken

Esta pregunta ya tiene muchas respuestas, pero en algunos casos puedes conformarte con algo más simple que todas. Si la cadena que está buscando es conocida (codificada), puede usar expresiones regulares sin comillas, etc.

Compruebe si una cadena comienza con 'ABC':

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

termina con 'ABC':

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

En mi caso simple, quería verificar si una cadena termina con una barra oblicua:

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

La ventaja: dado que es muy breve y simple, no es necesario definir una función (como endsWith()) como se muestra arriba.

Pero nuevamente, esta no es una solución para todos los casos, solo este muy específico.

Respondido 30 Oct 18, 22:10

no es necesario codificar la cadena. la expresión regular enlatado Sea dinámico. - Ryan

@self es cierto, pero si la cadena no está codificada, debe escapar de ella. Actualmente hay 2 respuestas a esta pregunta que lo hacen. Esto es fácil, pero complica un poco el código. Entonces, mi punto fue que para casos muy simples, donde la codificación es posible, puede mantenerlo simple. - noamtm

Actualización de PHP 8

PHP 8 incluye nuevo str_starts_with y str_ends_with funciones que finalmente proporcionan una solución eficaz y conveniente a este problema:

$str = "beginningMiddleEnd";
if (str_starts_with($str, "beg")) echo "printed\n";
if (str_starts_with($str, "Beg")) echo "not printed\n";
if (str_ends_with($str, "End")) echo "printed\n";
if (str_ends_with($str, "end")) echo "not printed\n";

El RFC para esta función proporciona más información, y también una discusión de los méritos y problemas de las implementaciones obvias (y no tan obvias) del espacio de usuario.

Respondido el 03 de enero de 21 a las 02:01

La expresión regular funciona arriba, pero con los otros ajustes también sugeridos anteriormente:

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

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

respondido 16 nov., 12:19

en php para operaciones de cadena, el orden de los parámetros es $ pajar, $ aguja. estas funciones están al revés y actúan como funciones de matriz donde el orden es en realidad $ aguja, $ pajar. - Andrés

Si la velocidad es importante para ti, prueba esto (creo que es el método más rápido)

Funciona solo para cadenas y si $ haystack tiene solo 1 carácter

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

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

$str='|apples}';
echo startsWithChar('|',$str); //Returns true
echo endsWithChar('}',$str); //Returns true
echo startsWithChar('=',$str); //Returns false
echo endsWithChar('#',$str); //Returns false

Respondido 17 ago 20, 13:08

esta es probablemente la respuesta más eficiente porque no usa ninguna función como extra, solo una cadena habitual ... - user1646111

Probablemente debería verificar si la cadena tiene al menos un carácter y los dos parámetros intercambiados: a1an

Creativo. Agujas que contienen montones de heno. Por cierto, hay algo feo menguante con: endsWithChar('','x'), pero el resultado es correcto - Tino

Me gusta tu respuesta, pero es bastante divertida, ... la aguja y el pajar son al revés :) ... es decir, buscarías una aguja en un pajar, por lo tanto, debería ser: return ($ aguja == = $ pajar [0]); , pero buena respuesta, gracias! - Heider Sati

@HeiderSati: ¡Gran observación! De eso estaba hablando @Tino Creative. Needles which contain haystacks.... No presté suficiente atención. ¡Gracias! Lo arreglé. :) - hermosa

Solución más rápida endsWith ():

# 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();

Resultados de referencia:

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

Respondido 15 Oct 20, 18:10

+1 por tomarse el tiempo para comparar diferentes soluciones y compararlas. También debe mencionar qué versión de PHP utilizó, ya que las optimizaciones se realizan a medida que evoluciona el lenguaje. He visto mejoras dramáticas en las funciones de comparación de cadenas de una versión de PHP a otra :) - Christophe Deliens

haciéndose eco de @ChristopheDeliens y su solicitud de proporcionar la versión PHP. Ejecuté su prueba en 7.3.2 y obtuve resultados similares FWIW. - Jeff

Aquí hay dos funciones que no introducen una cadena temporal, lo que podría ser útil cuando las agujas son sustancialmente grandes:

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

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

Respondido 21 Feb 14, 06:02

+1 funciona desde PHP5.1 y en mi humilde opinión la mejor respuesta. Pero endsWidth deberían hacer return $needle==='' || substr_compare(... por lo que funciona como se esperaba para -strlen($needle)===0 que, sin la solución, hace endsWith('a','') retorno false - Tino

@Tino Gracias ... siento que es un error en substr_compare() de hecho, he añadido un PR para arreglar eso :) - Jack

La llamada endsWith('', 'foo') desencadena una Advertencia: "substr_compare (): La posición inicial no puede exceder la longitud inicial de la cadena". Tal vez sea otro error en substr_compare(), pero para evitarlo, necesita una verificación previa como ...|| (strlen($needle) <= strlen($haystack) && substr_compare(...) === 0); - gx_

@gx_ No es necesario reducir la velocidad con más código. Solo usa return $needle === '' || @substr_compare(.. para suprimir esta advertencia. - Tino

Me doy cuenta de que esto se ha terminado, pero es posible que desee ver strncmp ya que le permite poner la longitud de la cadena para comparar, así:

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

Respondido el 17 de Septiembre de 09 a las 06:09

¿Cómo harías para terminar con esto? - mpen

@Mark: puede ver la respuesta aceptada, pero prefiero usar strncmp principalmente porque creo que es más seguro. - James Black

Me refiero a strncmp específicamente. No puede especificar un desplazamiento. Eso significaría que su función endsWith tendría que usar un método completamente diferente. - mpen

@Mark - Para fines Con solo usaría strrpos (php.net/manual/en/function.strrpos.php), pero, en general, siempre que vaya a utilizar strcmp, probablemente, strncmp sea una opción más segura. - James Black

Aquí hay una versión segura de varios bytes de la respuesta aceptada, funciona bien para cadenas UTF-8:

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);
}

Respondido 17 Abr '19, 20:04

Estoy bastante seguro de que esto es solo una pérdida de CPU. todo lo que necesita verificar, para StarstWith y EndsWith, es simplemente verificar que los bytes coincidan, y eso es exactamente lo que está haciendo la respuesta aceptada. este 1 es una pérdida de tiempo calculando el número de caracteres utf8 de la aguja, y dónde está la posición del n-ésimo carácter utf8 del pajar ... creo, sin estar 100% seguro, esto es solo una pérdida de CPU. ¿se le ocurre un caso de prueba real en el que la respuesta aceptada falle y este no? - Hanshenrik

@hanshenrik - podría suceder por cierto, en el caso muy raro cuando busca una cadena que contiene los mismos bytes que un UTF8 pero falta la mitad del último carácter. Por ejemplo, tienes unicode C5 91 (letra "ő") y buscas C5 (letra "Å"), no debería darte una coincidencia. Por otro lado, claro, ¿por qué buscarías en un pajar utf una aguja que no sea utf ... Pero para los controles a prueba de balas, esto debe considerarse una posibilidad? - dkellner

In startsWith debería ser $length = mb_strlen($needle, 'UTF-8'); - Thomas Kekeisen

@ThomasKekeisen Gracias, lo arreglé. - Vahid Amiri

La solución aceptada (bueno, actualmente aceptada) ya es multibyte segura. En realidad, es binario seguro, lo que es una garantía aún más sólida. - Jon

Puedes usar strpos y strrpos

$bStartsWith = strpos($sHaystack, $sNeedle) == 0;
$bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle);

Respondido 29 Jul 16, 10:07

¿Debería usar triple igual aquí? strpos($sHaystack, $sNeedle) == 0 como este strpos($sHaystack, $sNeedle) === 0? Veo un error, cuando false == 0 evalúa a true. - Kalyan

Palabras breves y fáciles de entender sin expresiones regulares.

startsWith () es sencillo.

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

endsWith () usa el strrev () un poco elegante y lento:

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

Respondido el 29 de junio de 11 a las 02:06

@FrancescoMM: strpos no es la "herramienta adecuada"... ¿Por qué? Entonces, ¿cuáles son las "herramientas adecuadas"? EDIT: Leí tu respuesta a continuación. Pensé que la programación es como una invención usando los recursos que tienes ... Entonces no hay nada correcto o incorrecto ... solo funciona o no funciona ... el rendimiento es secundario. - Fr0zenFyr

"¿Porque es una herramienta para buscar, no para comparar?" Cit. Aristóteles - FrancescoMM

Centrándose en startswith, si está seguro de que las cadenas no están vacías, agregar una prueba en el primer carácter, antes de la comparación, el strlen, etc., acelera un poco las cosas:

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

De alguna manera es (20% -30%) más rápido. Agregar otra prueba de caracteres, como $ haystack {1} === $ needle {1} no parece acelerar mucho las cosas, incluso puede ralentizarlas.

=== parece más rápido que == Operador condicional (a)?b:c parece más rápido que if(a) b; else c;


Para aquellos que preguntan "¿por qué no usar strpos?" llamar a otras soluciones "trabajo innecesario"


strpos es rápido, pero no es la herramienta adecuada para este trabajo.

Para entender, aquí hay una pequeña simulación como ejemplo:

Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c

¿Qué hace la computadora "adentro"?

    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

Suponiendo que strlen no itera toda la cadena (pero incluso en ese caso), esto no es conveniente en absoluto.

Respondido 28 Jul 13, 19:07

Solo hay una aceleración si los primeros personajes son diferentes. - Jack

@Jack sí, por supuesto, la idea es que estadísticamente eso sucede, por lo que la aceleración es generalmente de un 20% a un 30% en todo el conjunto de pruebas (incluidos los casos en los que no es diferente). Ganas mucho cuando son diferentes y pierdes muy poco cuando no lo son. En promedio, ganas ese 30% (varía según el conjunto, pero sobre todo ganas velocidad en pruebas grandes) - FrancescoMM

"pero no es la herramienta adecuada para este trabajo"... ¿Alguna cita? - Fr0zenFyr

WTF. Enumeré todo el proceso a continuación, ¿a quién debo citar, más que eso? ¿Usaría una función que busca hasta el final de una cadena para decirle que el primer carácter no es una 'a'? ¿A quién le importa? No es la herramienta adecuada porque es una herramienta para buscar, no para comparar, ¡no es necesario citar a Aristóteles para decir lo obvio! - FrancescoMM

Espero que la respuesta a continuación sea eficiente y también simple:

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

Respondido 18 Oct 13, 17:10

Normalmente termino yendo con una biblioteca como subrayado-php en estos días.

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   

La biblioteca está llena de otras funciones útiles.

Respondido el 23 de enero de 15 a las 06:01

El https://www.youtube.com/watch?v=xB-eutXNUMXJtA&feature=youtu.be by mpen es increíblemente minucioso, pero, desafortunadamente, el punto de referencia proporcionado tiene una supervisión muy importante y perjudicial.

Debido a que cada byte en agujas y pajar es completamente aleatorio, la probabilidad de que un par aguja-pajar difiera en el primer byte es 99.609375%, lo que significa que, en promedio, alrededor de 99609 de los 100000 pares diferirán en el primer byte. . En otras palabras, el índice de referencia está fuertemente sesgado hacia startswith implementaciones que verifican el primer byte explícitamente, como strncmp_startswith2 hace.

Si el ciclo de generación de pruebas se implementa de la siguiente manera:

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 />";

los resultados de la evaluación comparativa cuentan una historia ligeramente diferente:

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

Por supuesto, es posible que este punto de referencia aún no sea perfectamente imparcial, pero también prueba la eficiencia de los algoritmos cuando se le dan agujas que coinciden parcialmente.

Respondido el 21 de Septiembre de 16 a las 17:09

PHP 8.0

A partir del PHP 8.0 hay dos nuevos métodos implementados: str_starts_with y str_ends_with. Sin embargo, distinguen entre mayúsculas y minúsculas. Las funciones devuelven verdadero o falso.

$str = 'apples';

var_dump(str_starts_with($str, 'a')); // bool(true)
var_dump(str_starts_with($str, 'A')); // bool(false)

var_dump(str_ends_with($str, 's')); // bool(true)
var_dump(str_ends_with($str, 'S')); // bool(false)

Hasta PHP 8.0

El más rápido startsWith función en @mpen respuesta: https://stackoverflow.com/a/7168986/7082164

El más rápido endsWith función en @Lucas_Bustamante respuesta: https://stackoverflow.com/a/51491517/7082164

Respondido el 02 de diciembre de 20 a las 19:12

en breve:

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

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

Respondido 20 Abr '12, 01:04

Házlo más rápido:

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)));
}

Esa línea adicional, comparando el primer carácter de las cadenas, puede hacer que el caso falso regrese inmediatamente, lo que hace que muchas de sus comparaciones sean mucho más rápidas (7 veces más rápido cuando medí). En el caso real, no paga prácticamente ningún precio en rendimiento por esa única línea, así que creo que vale la pena incluirla. (Además, en la práctica, cuando prueba muchas cadenas para un fragmento inicial específico, la mayoría de las comparaciones fallarán, ya que en un caso típico está buscando algo).

NOTA: el error en el comentario de @ Tino a continuación ya se ha solucionado

En cuanto a cadenas vs enteros

Si desea forzar la comparación de cadenas (es decir, espera que startsWith ("1234", 12) sea verdadero), necesitará un encasillado:

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

No creo que sea necesario, pero es un caso límite interesante, que lleva a preguntas como "¿el verdadero booleano comienza por en?" - así que tú decides, pero asegúrate de decidir para siempre.

Respondido el 17 de diciembre de 20 a las 11:12

Error en tu código: startsWith("123", "0") da true - Tino

¡Sí, ha ocurrido una mala comprobación de $! ¡Lo siento! (Solo quería ilustrar el concepto en la línea 3) - dkellner

@Tino Diría que podríamos eliminar estos 2 comentarios ahora, ¿no estás de acuerdo? Quiero decir, punto tomado, está arreglado y han pasado 2 años. - dkellner

Esto puede funcionar

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

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

contestado el 23 de mayo de 17 a las 15:05

El substr la función puede volver false en muchos casos especiales, así que aquí está mi versión, que trata estos problemas:

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
}

Pruebas (true significa bueno):

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'));

También el substr_compare También vale la pena mirar la función. http://www.php.net/manual/en/function.substr-compare.php

Respondido 21 Feb 12, 15:02

¿Por qué no lo siguiente?

//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 . "!";
}

Salida:

Valor encontrado al principio de valuehaystack!

Tenga en cuenta, strpos devolverá falso si la aguja no se encontró en el pajar, y devolverá 0 si, y solo si, la aguja se encontró en el índice 0 (también conocido como el principio).

Y aquí termina con:

$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 . "!";
}

En este escenario no hay necesidad de una función startsWith () como

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

devolverá verdadero o falso con precisión.

Parece extraño que sea así de simple con todas las funciones salvajes corriendo desenfrenadas aquí.

Respondido 12 Abr '14, 23:04

Parece extraño que si estás buscando "xy" dentro de la cadena "abcdefghijklmxyz" en lugar de simplemente comparar "x" con "a" y devolver FALSE, miras todos los caracteres de "a" a "m" y terminas encontrando "xy" dentro de la cadena, y finalmente devuelve FALSE porque la posición de la misma no es cero. Esto es lo que estás haciendo, y es más extraño y más salvaje que cualquier otra función desenfrenada aquí. - FrancescoMM

La simplicidad está en la mecanografía, no en la lógica. - Bill Effin Murray

No es tanto la lógica, es la posible optimización lo que apuntaba Francsco. Utilizando strpos() será lento excepto cuando coincida. strncmp() sería mucho mejor en este caso. - Alexis Wilke

Cuando realiza funciones de nivel tan bajo, normalmente desea optar por la solución con mayor velocidad optimizada, sin importar cuán compleja sea, ya que esto se llamará millones de veces. Cada microsegundo que ganes o pierdas aquí marcará una diferencia muy real. Así que es mejor modificarlo (y luego olvidarse de la complejidad, ahora que tiene la función), en lugar de buscar la apariencia y perder una cantidad de tiempo horrible más tarde cuando ni siquiera sabe qué salió mal. Imagínese comprobar una cadena de 2 GB que no coincide. - dkellner

Lo haría así

     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;
        }

Respondido 07 Oct 14, 17:10

Olvidar devolver falso si no coincide. Errgo incorrecto, ya que el valor de retorno de una función no debe 'asumirse', pero sé lo que está buscando al menos en comparación con otras respuestas. - Spoo

Basado en la respuesta de James Black, aquí está su versión final Con:

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);

}

Nota: He cambiado la parte if-else por la función startsWith de James Black, porque strncasecmp es en realidad la versión de strncmp que no distingue entre mayúsculas y minúsculas.

Respondido 30 Oct 09, 03:10

Tenga en cuenta que strrev() is creativo pero muy costoso, especialmente si tiene cadenas de digamos ... 100Kb. - Alexis Wilke

Utilizan === en lugar de == para estar seguro. 0 es igual a muchas cosas en PHP. - nawfal

Muchas de las respuestas anteriores funcionarán igual de bien. Sin embargo, esto es posiblemente lo más breve posible y haga que haga lo que desee. Simplemente indica que te gustaría que 'devuelva verdadero'. Así que he incluido soluciones que devuelven verdadero / falso booleano y verdadero / falso textual.

// 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';
}

Respondido 27 Oct 14, 16:10

Cierto. Sin embargo, Peter estaba pidiendo una función que funcionara con cadenas de caracteres. No obstante, he actualizado mi respuesta para apaciguarlos. - ThatOneCoder

Después de la edición, su solución ahora está completamente obsoleta. Vuelve 'true' y 'false' como cadenas, que son a la vez true en un sentido booleano. Es un buen patrón para algo como underhanded.xcott.com aunque ;) - Tino

Bueno, Peter acaba de decir que quería que volviera a ser "verdadero". Así que pensé en devolverle lo que pidió. He añadido ambas versiones, por si acaso no es lo que quería. - ThatOneCoder

Sin copia y sin bucle interno:

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;
}

contestado el 11 de mayo de 20 a las 01:05

¡esto debería ser mucho más rápido que la implementación de MrHus! podría compararlo - Hanshenrik

También puede usar expresiones regulares:

function endsWith($haystack, $needle, $case=true) {
  return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}

Respondido el 22 de diciembre de 10 a las 17:12

$ aguja debe escaparse con preg_quote($needle, '/'). - Timo Tijhof

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.