Qual è il test più efficiente per verificare se una stringa PHP termina con un'altra stringa?


Risposte:


152

Quello che ha detto Assaf è corretto. C'è una funzione incorporata in PHP per fare esattamente questo.

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

Se $testè più lungo di $strPHP verrà visualizzato un avviso, quindi è necessario verificarlo prima.

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

Bello. Sembra che il confronto sul posto sia più veloce di substr (), come ha sottolineato Assaf.
Jason Cohen

2
La risposta di mcrumley è interessante, ma dovrebbe usare "===" invece di "==". '===' è più severo e di solito fa quello che vuoi, mentre '==' può portare a brutte sorprese. Il terzo snippet di codice di mcrumley è corretto, ma i primi due non lo sono. substr_compare () restituisce false in alcuni casi di errore. In PHP, false == 0, quindi gli snippet di codice segnalerebbero che la stringa è stata trovata. Con ===, questo non accade.
jcsahnwaldt Ripristina Monica il

1
Oggi mi sono imbattuto in un bug che romperà la soluzione che hai fornito da PHP 5.5.11 in poi. bugs.php.net/bug.php?id=67043
user2180613

3 chiamate di funzione in testa non lo rendono più veloce.
Thanh Trung

66

Questo metodo è leggermente più costoso per la memoria, ma è più veloce:

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

È meglio quando sai esattamente qual è l'ago, in modo da poterlo codificare al contrario. Se si inverte l'ago in modo programmatico, diventa più lento del metodo precedente.


2
-1 Dubito seriamente che sia più veloce ed è complicato (bello ma di solito non utile). Se il pagliaio non finisce con l'ago, stripositererà l'intera corda nel caso peggiore mentre substr_compareconfronterà al massimo la lunghezza dell'ago. Sì, substr_comparerichiede il calcolo della lunghezza del pagliaio (e un ago molto più piccolo), ma questo metodo lo richiede e lo copia per intero, ed eventualmente converte l'intera cosa in minuscolo per l'avvio.
David Harkness

approccio interessante ma inefficiente (come menzionato nella risposta stessa) in molti casi! Ancora un voto positivo per essere stranamente creativi e dimostrare che ci possono sempre essere più modi per fare la stessa cosa che potresti mai immaginare. Saluti!
Fr0zenFyr

1
Ho provato e ho trovato questo metodo più veloce della risposta accettata. Anche se sia il pagliaio che l'ago vengono invertiti al volo, è più veloce.
Shumoapp

@DavidHarkness Hai testato per vedere se i tuoi dubbi erano giustificati?
Nathan

@ Nathan No, non vale la pena dedicare del tempo al benchmark poiché substr_compare()funziona bene.
David Harkness

61
$endsWith = substr_compare( $str, $test, -strlen( $test ) ) === 0

Offset negativo "inizia il conteggio dalla fine della stringa".


3
IMO è una delle migliori dalle soluzioni fornite
Roman Podlinov

+200 se potessi. L'intuizione chiave qui è che l'uso di una lunghezza negativa ottiene la parte finale della stringa. Puoi anche usare substr con la lunghezza -ve e fare un == contro $ test. Le altre risposte sono scarse.
Nick

11

Ecco un modo semplice per verificare se una stringa finisce con un'altra, fornendo strposun offset proprio dove dovrebbe essere trovata la stringa:

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

Semplice, e penso che funzionerà in PHP 4.


8

Dipende dal tipo di efficienza a cui tieni.

La tua versione usa più memoria a causa della copia extra dall'uso di substr.

Una versione alternativa potrebbe cercare nella stringa originale l'ultima occorrenza della sottostringa senza fare una copia, ma probabilmente sarebbe più lenta a causa di ulteriori test.

Probabilmente il modo più efficiente è eseguire il ciclo carattere per carattere dalla posizione -sterlen (test) fino alla fine della stringa e confrontare. Questa è la quantità minima di confronti che puoi sperare di fare e non viene utilizzata quasi nessuna memoria aggiuntiva.


5

Un altro modo sarebbe usare la strrposfunzione :

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

Ma non è più veloce.


3

Spero che la risposta di seguito possa essere efficiente e anche semplice:

$content = "The main string to search";
$search = "search";
//For compare the begining string with case insensitive. 
if(stripos($content, $search) === 0) echo 'Yes';
else echo 'No';

//For compare the begining string with case sensitive. 
if(strpos($content, $search) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case insensitive. 
if(stripos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';

//For compare the ending string with case sensitive. 
if(strpos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';

2

Non so se sia veloce o meno, ma per un singolo test di carattere, funzionano anche questi:

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

1

modo più semplice per controllarlo tramite un'espressione regolare

ad esempio per verificare se la posta fornita è gmail:

echo (preg_match("/@gmail\.com$/","example-email@gmail.com"))?'true':'false';

0

Penso che le funzioni inverse come strrchr () ti aiuterebbero a trovare la fine della stringa più velocemente.


0

Questo è puro PHP, senza chiamare funzioni esterne, ad eccezione di strlen .

function endsWith ($ends, $string)
{
    $strLength = strlen ($string);
    $endsLength = strlen ($ends);
    for ($i = 0; $i < $endsLength; $i++)
    {
        if ($string [$strLength - $i - 1] !== $ends [$i])
            return false;
    }
    return true;
}

0

per ago a carattere singolo:

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.