Pergunta

Como posso escrever duas funções que levariam uma corda e retorno se ele começa com o especificado de caracteres / string ou termina com ele?

Por exemplo:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
Foi útil?

Solução

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 isso se você não quiser usar um regex.

Outras dicas

Você pode usar substr_compare função para verificar start-com e fins-de-com:

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 deve ser uma das soluções mais rápidas em PHP 7 ( referência roteiro ) . Testado contra palheiros 8KB, várias agulhas de comprimento e casos completos, parciais e nenhum jogo. strncmp é um toque mais rápido para começa-com, mas não pode verificar fins-com.

Updated 23-Aug-2016

Funções

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

testes

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)

(Ordenado mais rápido para o mais 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)

(Ordenado mais rápido para o mais 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

Todas as respostas até agora parecem fazer um monte de trabalho desnecessário, strlen calculations, string allocations (substr), etc. As funções 'strpos' e 'stripos' devolver o índice da primeira ocorrência de $needle em $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;
}
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);
}

Credit Para :

verificar se uma string termina com outra corda

Verifique se uma string começa com outra corda

As funções de regex acima, mas com os outros ajustes também sugeridas acima:

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

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

Esta questão já tem muitas respostas, mas em alguns casos você pode se contentar com algo mais simples do que todos eles. Se a string que você está procurando é conhecida (codificado), você pode usar expressões regulares sem qualquer citando etc.

verificar se uma string começa com 'ABC':

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

termina com 'ABC':

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

No meu caso simples, eu queria verificar se uma string termina com Slash:

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

A vantagem:., Já que é muito curto e simples, você não tem que definir uma função (como endsWith()) como mostrado acima

Mas novamente -. Isso não é uma solução para cada caso, apenas um presente muito específico

Se a velocidade é importante para você, tente isso. (Eu acredito que é o método mais rápido)

Funciona apenas para cordas e se $ palheiro é de apenas 1 personagem

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

Aqui são duas funções que não introduzem uma cadeia temporária, que poderia ser útil quando as agulhas são substancialmente grande:

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

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

Sei que este tenha sido concluído, mas você pode querer olhar em strncmp , uma vez que permite que você coloque o comprimento da corda para comparar com, por isso:

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

endsWith Mais rápido () solução:

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

Índice de referência:

# 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 benchmark:

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

Você pode usar strpos e strrpos

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

curta e fácil de entender one-liners, sem expressões regulares.

startsWith () é para a frente.

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

endsWith () usa o pouco de fantasia e strrev lenta ():

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

Aqui está uma versão multi-byte da resposta aceita, ele funciona bem para UTF-8 cordas:

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

Focando startswith, se tiver certeza de cordas não estão vazios, adicionando um teste no primeiro char, antes da comparação, o strlen, etc., acelera as coisas um pouco:

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

É de certa forma (20% -30%) mais rápido. Adicionando outro teste char, como US $ palheiro {1} === $ agulha {1} não parece coisas speedup muito, pode até desacelerar.

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


Para aqueles perguntando "por que não usar strpos?" chamando outras soluções "trabalho desnecessário"


strpos é rápido, mas não é a ferramenta certa para este trabalho.

Para entender, aqui é um pouco de simulação como um exemplo:

Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c

O que o computador faz "dentro"?

    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

Assumindo strlen não iterate a corda toda (mas mesmo nesse caso), este não é conveniente a todos.

Espero que a seguir resposta pode ser eficiente e também simples:

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

Eu geralmente acabam indo com uma biblioteca como sublinhado-php estes dias.

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   

A biblioteca está cheia de outras funções úteis.

O resposta por MPEN é incrivelmente completa, mas, infelizmente, o ponto de referência fornecido tem uma supervisão muito importante e prejudicial.

Porque cada byte em agulhas e palheiros é completamente aleatória, a probabilidade de que um par de agulha-feno será diferente no primeiro byte é 99.609375%, o que significa que, em média, cerca de 99.609 das 100000 pares serão diferentes no muito primeiro byte. Em outras palavras, o benchmark é fortemente inclinado para implementações startswith que verificam o primeiro byte explicitamente, como strncmp_startswith2 faz.

Se o circuito de teste de geração em vez disso é implementado do seguinte modo:

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

Os resultados do benchmark contar uma história um pouco 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

É claro que essa referência pode ainda não ser perfeitamente imparcial, mas ele testa a eficiência dos algoritmos quando dadas agulhas parcialmente correspondentes também.

A função substr pode retornar false em muitos casos especiais, por isso aqui é a minha versão, que lida com estas questões:

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
}

Testes (meios true bom):

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

Além disso, a função substr_compare também vale a pena olhar. http://www.php.net/manual/en/function. substr-compare.php

Em resumo:

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

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

Isso pode funcionar

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

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

Por que não o seguinte?

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

Output:

valor encontrado no início da valuehaystack!

Tenha em mente, strpos retornará false se a agulha não foi encontrado no palheiro, e irá retornar 0 se, e somente se, a agulha foi encontrado no índice 0 (AKA o início).

E aqui está endsWith:

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

Neste cenário, não há necessidade para uma função startsWith () como

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

retornará verdadeira ou falsa precisão.

Parece estranho é este simples com todas as funções selvagens correndo solta aqui.

Eu faria isso como este

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

Apenas uma recomendação:

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

Essa linha extra, comparando o primeiro caractere das cordas, pode fazer a retorno caso false imediatamente , tornando, portanto, muitas das suas comparações muito mais rápido (7x mais rápido quando eu medi). No verdadeiro caso de você pagar praticamente nenhum preço no desempenho para esse única linha, então eu acho que vale a pena inclusive. (Além disso, na prática, quando você testar muitas cordas para uma específica começando pedaço, a maioria das comparações irá falhar uma vez que em um caso típico que você está procurando algo.)

Você também pode usar expressões regulares:

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

Muitas das respostas anteriores vai funcionar tão bem. No entanto, este é possivelmente tão curto quanto você pode fazê-lo e tê-lo fazer o que você deseja. Você só estado que você gostaria que ele 'return true'. Então eu incluí soluções que retorna booleano verdadeiro / falso eo verdadeiro / 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';
}

Com base na resposta de James Black, aqui está sua versão endsWith:

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:. Tenho trocado a parte if-else para a função startsWith de James Black, porque strncasecmp é realmente a versão case-insensitive de strncmp

Aqui está uma solução eficiente para PHP 4. Você pode obter resultados mais rápidos se em PHP 5 utilizando substr_compare vez 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;
}
$ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot

Não sei por que isso é tão difícil para as pessoas. Substr faz um grande trabalho e é eficiente como você não precisa procurar toda a cadeia se ele não corresponder.

Além disso, desde que eu não estou verificando valores inteiros, mas comparando strings não tem que ter necessariamente de se preocupar com o caso estrita ===. No entanto, === é um bom hábito de entrar.

function startsWith($haystack,$needle) {
  substring($haystack,0,strlen($needle)) == $needle) { return true; }
   return false;
}

function endsWith($haystack,$needle) {
  if(substring($haystack,-strlen($needle)) == $needle) { return true; }
   return false;
}

ou ainda melhor otimizado.

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

function endsWith($haystack,$needle) {
  return substring($haystack,-strlen($needle)) == $needle);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top