Какой самый эффективный тест на то, заканчивается ли строка PHP другой строкой?

125

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

$endsWith = substr( $str, -strlen( $test ) ) == $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;
}
mcrumley
источник
Ницца. Как заметил Ассаф, похоже, что сравнение на месте будет быстрее, чем substr ().
Джейсон Коэн,
2
Ответ Макрамли классный, но он должен использовать «===» вместо «==». '===' более строгий и обычно делает то, что вы хотите, в то время как '==' может привести к неприятным сюрпризам. Третий фрагмент кода Макрамли верен, но первые два - нет. substr_compare () возвращает false в некоторых случаях ошибки. В PHP false == 0, поэтому фрагменты кода будут сигнализировать о том, что строка найдена. С === этого не происходит.
jcsahnwaldt Reinstate Monica
1
Сегодня я столкнулся с ошибкой, которая нарушит работу решения, которое вы дали с PHP 5.5.11 и новее. bugs.php.net/bug.php?id=67043
user2180613
Накладные расходы на 3 вызова функций не делают его быстрым.
Thanh Trung
66

Этот метод немного дороже памяти, но он быстрее:

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

Это лучше всего, когда вы точно знаете, что такое игла, и можете жестко запрограммировать ее в обратном направлении. Если вы программно перевернете иглу, она станет медленнее, чем предыдущий метод.

jscheel
источник
2
-1 Очень сомневаюсь, что это быстрее и сложно (круто, но обычно не помогает). Если стог сена не заканчивается иглой, striposв худшем случае будет повторяться вся строка, тогда как substr_compareбудет сравниваться не более длины иглы. Да, substr_compareтребуется вычислить длину стога сена (и иголку гораздо меньшего размера), но этот метод требует этого и полного копирования, и, возможно, преобразования всего этого в нижний регистр для загрузки.
Дэвид Харкнесс,
крутой подход, но неэффективный (как уже упоминалось в самом ответе) во многих случаях! По-прежнему за то, что проявили странную креативность и продемонстрировали, что всегда может быть больше способов сделать то же самое, что вы можете себе представить. Ура!
Fr0zenFyr
1
Я протестировал и нашел этот метод быстрее, чем принятый ответ. Даже если и стог сена, и иголку поменять местами на лету, это будет быстрее.
Shumoapp 06
@DavidHarkness Вы проверяли, оправданы ли ваши сомнения?
Натан
@Nathan Нет, не стоит тратить время на тестирование, так как substr_compare()работает хорошо.
Дэвид Харкнесс
61
$endsWith = substr_compare( $str, $test, -strlen( $test ) ) === 0

Отрицательное смещение «начинает отсчет с конца строки».

Александр Яновец
источник
3
ИМО, это одно из лучших решений из предложенных
Роман Подлинов
+200, если бы мог. Ключевым моментом здесь является то, что при использовании отрицательной длины получается конечная часть строки. Вы также можете использовать substr с длиной -ve и выполнить == против $ test. Остальные ответы плохие.
Ник
11

Вот простой способ проверить, заканчивается ли одна строка другой, задав strposсмещение там, где она должна быть найдена:

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

Просто, и я думаю, что это будет работать в PHP 4.

Патрик Смит
источник
8

Это зависит от того, какая эффективность вам важна.

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

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

Вероятно, наиболее эффективный способ - выполнить цикл по символам от позиции -sterlen (тестовая) до конца строки и сравнить. Это минимальное количество сравнений, на которое вы можете надеяться, и почти не требует дополнительной памяти.

Ассаф Лави
источник
5

Другой способ - использовать strrposфункцию :

strrpos($str, $test) == strlen($str) - strlen($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';
Srinivasan.S
источник
2

Не знаю, быстро это или нет, но для односимвольного теста они тоже работают:

(array_pop(str_split($string)) === $test) ? true : false;
($string[strlen($string)-1] === $test) ? true : false;
(strrev($string)[0] === $test) ? true : false;
wloske
источник
1

самый простой способ проверить это с помощью регулярного выражения

например, чтобы проверить, является ли указанная почта gmail:

echo (preg_match("/@gmail\.com$/","example-email@gmail.com"))?'true':'false';
Бискрем Мухаммад
источник
0

Я думаю, что обратные функции, такие как strrchr (), помогут вам быстрее всего сопоставить конец строки.

tkotitan
источник
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;
}
Xesau
источник
0

для однозарядной иглы:

if (@strrev($haystack)[0] == $needle) {
   // yes, it ends...
}
kabantejay
источник