Який найефективніший тест на те, чи закінчується рядок PHP іншою рядком?


125

Стандартний спосіб PHP перевірити, чи $strзакінчується рядок підрядкою $test:

$endsWith = substr( $str, -strlen( $test ) ) == $test

Це найшвидший спосіб?



Ви можете знайти s($str)->endsWith($test)або s($str)->endsWithIgnoreCase($test)корисно, як це знайдено в цій самостійній бібліотеці .
каре

Відповіді:


152

Те, що сказав Ассаф, є правильним. У PHP є вбудована функція, щоб зробити саме це.

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

Якщо $testдовше, ніж $strPHP, надішлете попередження, тому спочатку потрібно перевірити це.

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

Приємно. Схоже, порівняння на місці було б швидше, ніж substr (), як зазначив Ассаф.
Джейсон Коен

2
Відповідь mcrumley класна, але вона повинна використовувати '===' замість '=='. '===' є більш суворим і зазвичай робить те, що ви хочете, тоді як '==' може призвести до неприємних сюрпризів. Третій фрагмент коду mcrumley правильний, але перші два - ні. substr_compare () повертає помилку в деяких випадках помилок. У PHP false == 0, тому фрагменти коду будуть сигналізувати про те, що рядок знайдено. З === цього не відбувається.
jcsahnwaldt Відновити Моніку

1
Я сьогодні зіткнувся з помилкою, яка порушить рішення, яке ви отримали від PHP 5.5.11 і далі. bugs.php.net/bug.php?id=67043
користувач2180613

Набір 3-х функціональних дзвінків не робить це найшвидшим.
Thanh Trung

66

Цей метод є трохи більш дорогим на пам’ять, але він швидший:

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

Це найкраще, коли ви точно знаєте, що таке голка, щоб ви могли жорстко кодувати її назад. Якщо голку перевернути програмно, вона стає повільнішою, ніж раніше.


2
-1 Я серйозно сумніваюся, що це швидше, і це хитро (круто, але зазвичай не корисно). Якщо стог сіна не закінчиться голкою, striposвін переверне всю нитку в гіршому випадку, тоді як substr_compareпорівняє максимум довжину голки. Так, substr_compareпотрібно обчислити довжину стога сіна (і набагато меншу голку), але цей метод вимагає цього і скопіювати його в повному обсязі, і, можливо, перетворити всю річ у малі регістри для завантаження.
Девід Гаркнесс

класний підхід, але неефективний (про що йдеться у самій відповіді) у багатьох випадках! Все-таки є нагодою за те, що ви дивно творчі та демонструєте, що завжди може бути більше способів зробити те саме, що ви коли-небудь можете собі уявити. Ура!
Fr0zenFyr

1
Я перевірив і знайшов цей метод швидше, ніж прийнятий відповідь. Навіть якщо і сіна, і голка повертаються на льоту, це швидше.
Shumoapp

@DavidHarkness Ви перевіряли, чи були ваші сумніви виправданими?
Натан

@Nathan Ні, не варто витрачати час на тестування, оскільки substr_compare()працює добре.
Девід Харкнесс

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

Від'ємне зміщення "починається відлік з кінця рядка".


3
IMO - це одне з найкращих із запропонованих рішень
Роман Подлінов,

+200, якби міг. Ключове розуміння тут полягає в тому, що з використанням негативної довжини виходить кінцева частина рядка. Ви також можете використовувати substr з довжиною -ve і робити == проти $ test. Інші відповіді погані.
Нік

11

Ось простий спосіб перевірити, чи закінчується одна рядок іншою, задавши strposзсув прямо там, де слід знайти рядок:

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

Відразу, і я думаю, що це працюватиме в PHP 4.


8

Це залежить від того, який тип ефективності ви дбаєте.

Ваша версія використовує більше пам’яті завдяки додатковій копії від використання substr.

Альтернативна версія може шукати оригінальну рядок для останнього появи підрядки без копіювання, але, ймовірно, буде повільнішою завдяки більшому тестуванню.

Напевно, найефективніший спосіб - це зробити цикл char-by-char з позиції -sterlen (test) до кінця рядка та порівняти. Це мінімальна кількість порівнянь, на яку ви можете сподіватися, і майже не використовується додаткова пам'ять.



3

Я сподіваюся, що наведена нижче відповідь може бути ефективною, а також простою:

$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

Не знаєте, швидко це це чи ні, але для одного тесту символів це також:

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

1

найпростіший спосіб перевірити це за допомогою регулярного вираження

наприклад, щоб перевірити, чи вказана пошта є gmail:

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

0

Я думаю, що зворотні функції, такі як strrchr (), допоможуть вам швидше зіставити кінець рядка.


0

Це чистий PHP, без виклику зовнішніх функцій, крім 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

для однократної голки:

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.