para - php string starts with substring




Las funciones startsWith() y endsWith() en PHP (20)

La solución más rápida con los extremos ():

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

Punto de referencia:

# 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

¿Cómo puedo escribir dos funciones que tomarían una cadena y devolverían si comienza con el carácter / cadena especificada o termina con ella?

Por ejemplo:

$str = '|apples}';

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

¿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 comienzo de valuehaystack!

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

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, es así de simple, con todas las funciones salvajes que se ejecutan aquí.


Aquí hay dos funciones que no introducen una cadena temporal, 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;
}

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

function startsWith($haystack, $needle)
{
    $length = mb_substr($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);
}

Espero que la siguiente respuesta sea eficiente y 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';

Esta pregunta ya tiene muchas respuestas, pero en algunos casos puede conformarse con algo más simple que todos ellos. Si la cadena que está buscando es conocida (codificada), puede usar expresiones regulares sin ninguna cita, 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 comprobar si una cadena termina con una barra:

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

La ventaja: ya que es muy corto y simple, no tiene que definir una función (como endsWith() ) como se muestra arriba.

Pero, de nuevo, esto no es una solución para cada caso, solo este muy específico.


Generalmente termino yendo con una biblioteca como underscore-php 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.


La answer de es increíblemente completa, pero, desafortunadamente, el punto de referencia proporcionado tiene una supervisión muy importante y perjudicial.

Debido a que cada byte en las agujas y pajares es completamente aleatorio, la probabilidad de que un par de aguja-pajar difiera en el primer byte es 99. 609375%, lo que significa que, en promedio, aproximadamente 99609 de los 100000 pares serán diferentes en el primer byte. . En otras palabras, el punto de referencia está fuertemente startswith hacia el startswith implementaciones que comprueban explícitamente el primer byte, como hace strncmp_startswith2 .

Si el bucle generador de prueba 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 referencia 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, este punto de referencia todavía puede no ser perfectamente imparcial, pero prueba la eficiencia de los algoritmos cuando se les da agujas parcialmente coincidentes también.


La función substr puede devolver false en muchos casos especiales, por lo 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'));

Además, la función substr_compare también vale la pena mirar. http://www.php.net/manual/en/function.substr-compare.php


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

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

Si está seguro de que las cadenas no están vacías, si se enfoca en los inicios, al agregar una prueba en el primer char, antes de la comparación, el strlen, etc.

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 char, como $ haystack {1} === $ needle {1} no parece acelerar mucho las cosas, incluso puede disminuir la velocidad.

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

Para aquellos que preguntan "¿por qué no usar strpos?" Llamando 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.


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

Funciona solo para cadenas y si $ haystack es solo 1 caracter

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

Unas líneas cortas y fáciles de entender sin expresiones regulares.

startsWith () es sencillo.

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

endsWith () usa el strrev () ligeramente sofisticado y lento:

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

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

Lo haria asi

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

Sólo una recomendación:

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

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


Aquí hay una solución eficiente para PHP 4. Puede obtener resultados más rápidos si usa PHP 5 usando en substr_comparelugar de 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;
}

Muchas de las respuestas anteriores funcionarán igual de bien. Sin embargo, es posible que esto sea lo más breve que pueda y haga que haga lo que desee. Solo dices que te gustaría que "vuelva a ser verdadero". Así que he incluido soluciones que devuelven boolean true / false y textual true / false.

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

$ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot

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

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





string