Domanda

Come posso scrivere due funzioni che prenderebbero una stringa e ritornerebbero se inizia con il carattere / stringa specificato o finisce con esso?

Ad esempio:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
È stato utile?

Soluzione

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

Usalo se non vuoi usare una regex.

Altri suggerimenti

Puoi usare substr_compare funzione per verificare inizio-e fine-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;
}

Questa dovrebbe essere una delle soluzioni più veloci su PHP 7 ( script di benchmark ) . Testato contro covoni di fieno da 8KB, aghi di varie lunghezze e casi completi, parziali e senza corrispondenza. strncmp è un tocco più veloce all'inizio, ma non può controllare finisce con.

Aggiornato il 23 agosto 2016

Funzioni

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

Test

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

Risultati (PHP 7.0.9)

(Ordinati dal più veloce al più 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

Risultati (PHP 5.3.29)

(Ordinati dal più veloce al più 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

startwith_benchmark.php

Tutte le risposte finora sembrano fare un sacco di lavoro inutile, calcoli strlen , allocazioni di stringhe (substr) , ecc. 'strpos' e le funzioni 'stripos' restituiscono l'indice della prima occorrenza di $ ago in $ pagliaio :

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

Credito a :

Controlla se una stringa finisce con un'altra stringa

Controlla se una stringa inizia con un'altra stringa

La regex funziona sopra, ma con le altre modifiche suggerite sopra:

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

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

Questa domanda ha già molte risposte, ma in alcuni casi puoi accontentarti di qualcosa di più semplice di tutte. Se la stringa che stai cercando è nota (codificata), puoi usare espressioni regolari senza virgolette, ecc.

Controlla se una stringa inizia con 'ABC':

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

termina con "ABC":

preg_match('/ABC$/', $myString); // "
preg_match('#/$#', $myPath);   // Use "#" as delimiter instead of escaping slash
quot; here means end of string

Nel mio caso semplice, volevo verificare se una stringa termina con una barra:

<*>

Il vantaggio: poiché è molto breve e semplice, non è necessario definire una funzione (come EndWith () ) come mostrato sopra.

Ma ancora una volta - questa non è una soluzione per ogni caso, solo questa molto specifica.

Se la velocità è importante per te, prova questo (credo che sia il metodo più veloce)

Funziona solo per le stringhe e se $ haystack ha solo 1 carattere

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

Ecco due funzioni che non introducono una stringa temporanea, che potrebbero essere utili quando gli aghi sono sostanzialmente grandi:

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

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

Mi rendo conto che questo è stato completato, ma potresti voler guardare strncmp poiché ti consente di confrontare la lunghezza della stringa con cui confrontarla, quindi:

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

La soluzione EndWith () più veloce:

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

Indice di riferimento:

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

Risultati 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

Puoi utilizzare strpos e strrpos

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

One-line brevi e di facile comprensione senza espressioni regolari.

startWith () è semplice.

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

EndWith () usa strrev () leggermente elaborato e lento:

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

Ecco una versione sicura multi-byte della risposta accettata, funziona bene per le stringhe 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);
}

Concentrarsi sugli avvii con, se sei sicuro che le stringhe non siano vuote, aggiungendo un test sul primo carattere, prima del confronto, della tensione, ecc., acceleri un po 'le cose:

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

È in qualche modo (20% -30%) più veloce. L'aggiunta di un altro test del carattere, come $ pagliaio {1} === $ ago {1} non sembra accelerare molto le cose, potrebbe persino rallentare.

=== sembra più veloce di == L'operatore condizionale (a)? B: c sembra più veloce di se (a) b; altro c;


Per coloro che chiedono " perché non usare strpos? " chiamando altre soluzioni "lavoro superfluo"


strpos è veloce, ma non è lo strumento giusto per questo lavoro.

Per capire, ecco una piccola simulazione come esempio:

Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c

Che cosa fa il computer " 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

Supponendo che strlen non esegua l'iterazione dell'intera stringa (ma anche in quel caso) ciò non è affatto conveniente.

Spero che la risposta di seguito possa essere efficace e semplice:

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

Di solito finisco con una libreria come underscore-php in questi giorni.

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 libreria è piena di altre utili funzioni.

La risposta di mpen è incredibilmente approfondito, ma, sfortunatamente, il benchmark fornito ha una supervisione molto importante e dannosa.

Poiché ogni byte in aghi e pagliai è completamente casuale, la probabilità che una coppia ago-pagliaio differisca sul primo byte è del 99.609375%, il che significa che, in media, circa 99609 delle 100000 coppie differiranno sulla primissimo byte. In altre parole, il benchmark è fortemente distorto dalle implementazioni di startwith che controllano esplicitamente il primo byte, come fa strncmp_startswith2 .

Se il ciclo di generazione del test è invece implementato come segue:

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

i risultati del benchmark raccontano una storia leggermente diversa:

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

Naturalmente, questo benchmark potrebbe non essere ancora perfettamente imparziale, ma verifica l'efficienza degli algoritmi anche quando vengono forniti aghi parzialmente corrispondenti.

La funzione substr può restituire false in molti casi speciali, quindi ecco la mia versione, che tratta questi problemi:

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
}

Test ( true significa buono):

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

Inoltre, vale la pena cercare anche la funzione substr_compare . http://www.php.net/manual/en/function. substr-compare.php

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

Potrebbe funzionare

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

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

Perché non quanto segue?

//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:

  

Trovato valore all'inizio di valuehaystack!

Tieni presente che strpos restituirà false se l'ago non è stato trovato nel pagliaio e restituirà 0 se, e solo se, l'ago è stato trovato nell'indice 0 (AKA all'inizio).

Ed ecco finisce 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 . "!";
}

In questo scenario non è necessaria una funzione startWith () come

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

restituirà vero o falso con precisione.

Sembra strano che sia così semplice con tutte le funzioni jolly che imperversano qui.

Lo farei così

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

Solo una raccomandazione:

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

Quella riga aggiuntiva, confrontando il primo carattere delle stringhe, può rendere false case restituisce immediatamente , quindi effettua molti dei tuoi confronti molto più veloce (7 volte più veloce quando ho misurato). Nel vero caso non paghi praticamente nessun prezzo in termini di prestazioni per quella singola linea, quindi penso che valga la pena includerlo. (Inoltre, in pratica, quando si verificano molte stringhe per un blocco iniziale specifico, la maggior parte dei confronti fallisce poiché in un caso tipico si sta cercando qualcosa.)

Puoi anche usare espressioni regolari:

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

Molte delle risposte precedenti funzioneranno altrettanto bene. Tuttavia, questo è probabilmente il più breve possibile e farlo fare quello che desideri. Afferma semplicemente che ti piacerebbe che "ritornasse vero". Quindi ho incluso soluzioni che restituiscono il vero / falso booleano e il vero / falso testuale.

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

Basato sulla risposta di James Black, ecco le sue estremità con la versione:

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: ho scambiato la parte if-else con la funzione start di James Black con la funzione, perché strncasecmp è in realtà la versione senza distinzione tra maiuscole e minuscole di strncmp.

Ecco una soluzione efficiente per PHP 4. Puoi ottenere risultati più rapidi se su PHP 5 usando substr_compare invece di 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

Non so perché sia ??così difficile per le persone. Substr fa un ottimo lavoro ed è efficiente in quanto non è necessario cercare l'intera stringa se non corrisponde.

Inoltre, poiché non sto controllando i valori interi ma confrontando le stringhe non devo necessariamente preoccuparmi del caso rigoroso ===. Tuttavia, === è una buona abitudine per entrare.

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

o anche meglio ottimizzato.

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

function endsWith($haystack,$needle) {
  return substring($haystack,-strlen($needle)) == $needle);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top