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.