функции functionsWith () и окончание () в PHP

1216

Как я могу написать две функции, которые берут строку и возвращаются, если она начинается с указанного символа/строки или заканчивается им?

Например:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
  • 13
    Посмотрите класс Str Laravel для startWith () и endWith () для хорошо протестированных методов. Пограничные случаи встречались, поэтому широкое использование этого кода является преимуществом.
  • 1
    Вы могли бы найти s($str)->startsWith('|') и s($str)->endsWith('}') полезными, как это можно найти в этой автономной библиотеке .
Показать ещё 2 комментария
Теги:
string

30 ответов

1292
Лучший ответ
function startsWith($haystack, $needle)
{
     $length = strlen($needle);
     return (substr($haystack, 0, $length) === $needle);
}

function endsWith($haystack, $needle)
{
    $length = strlen($needle);

    return $length === 0 || 
    (substr($haystack, -$length) === $needle);
}

Используйте это, если вы не хотите использовать регулярное выражение.

  • 14
    +1 Это чище, чем принятый ответ. Кроме того, $length не требуется в последней строке endsWith() .
  • 0
    имена переменных неясны. Например, char - это строка, а не один символ. Возможно, рассмотрим переименование параметров в обычный php $ haystack и $ needle.
Показать ещё 28 комментариев
891

Можно использовать strrpos и strpos для проверки начала и конца, соответственно.

Обратите внимание, что использование strrpos для проверки начинается с и strpos для проверки концов с возвратом как можно скорее, а не проверкой всей строки до конца. Кроме того, это решение не создает временную строку. Подумайте, объясните причину, предшествующую downvoting. Просто потому, что f-wit в DWTF не понимает, как работает эта функция или думает, что есть только одно решение, это не значит, что этот ответ неверен.

function startsWith($haystack, $needle) {
    // search backwards starting from haystack length characters from the end
    return $needle === ''
      || strrpos($haystack, $needle, -strlen($haystack)) !== false;
}

function endsWith($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;
}

Тесты и результаты (сравните с этим):

startsWith('abcdef', 'ab') -> true
startsWith('abcdef', 'cd') -> false
startsWith('abcdef', 'ef') -> false
startsWith('abcdef', '') -> true
startsWith('', 'abcdef') -> false

endsWith('abcdef', 'ab') -> false
endsWith('abcdef', 'cd') -> false
endsWith('abcdef', 'ef') -> true
endsWith('abcdef', '') -> true
endsWith('', 'abcdef') -> false

Примечание: функции strncmp и substr_compare будут превосходить эту функцию.

  • 65
    Этот ответ добрался до Daily WTF! : D См. Thedailywtf.com/articles/…
  • 0
    Обратите внимание, что комментарии @DavidWallace и @FrancescoMM относятся к более старой версии этого ответа. В текущем ответе используются strrpos которые (должны) немедленно завершиться неудачей, если стрелка не соответствует началу стога сена.
Показать ещё 4 комментария
227

Обновлено 23 августа 2016 года

Функции

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

Испытания

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

Результаты (PHP 7.0.9)

(Отсортировано быстрее всего медленнее)

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

Результаты (PHP 5.3.29)

(Отсортировано быстрее всего медленнее)

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

startswith_benchmark.php

  • 3
    Если строки не пусты, как в ваших тестах, это на самом деле как-то (на 20-30%) быстрее: function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;} Я добавил ответ ниже.
  • 0
    @FrancescoMM Я включил вашу версию в мои тесты. Это не похоже на правду; по крайней мере, когда первая буква имеет шанс 1 на 64 совпадения.
Показать ещё 19 комментариев
121

Все ответы до сих пор, похоже, выполняют множество ненужных работ, strlen calculations, string allocations (substr) и т.д. Функции 'strpos' и 'stripos' возвращают индекс первого вхождения $needle в $haystack:

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;
}
  • 2
    endsWith() имеет ошибку. Его первая строка должна быть (без -1): $expectedPosition = strlen($haystack) - strlen($needle);
  • 0
    Исправлено, спасибо
Показать ещё 13 комментариев
43
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);
}

Кредит:

Проверьте, заканчивается ли строка с другой строкой

Проверьте, начинается ли строка с другой строки

  • 1
    strtolower - не лучший способ сделать регистронезависимыми функции. В некоторых регионах обсадная колонна является более сложной, чем просто верхняя и нижняя.
  • 7
    Я вижу жалобы и никакого решения ... Если вы скажете, что это плохо, то вам следует привести пример того, как это должно быть.
Показать ещё 1 комментарий
25

Регулярное выражение действует выше, но с другими настройками, предложенными выше:

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

 function endsWith($needle, $haystack) {
     return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
 }
  • 2
    в php для строковых операций порядок параметров равен $ haystack, $ needle. эти функции обращены назад и действуют как функции массива, где порядок на самом деле равен $ needle, $ haystack.
22

Если скорость важна для вас, попробуйте это. (Я считаю, что это самый быстрый метод)

Работает только для строк, а если $haystack - всего 1 символ

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
  • 1
    это, вероятно, самый эффективный ответ, потому что не использует какую-либо функцию в качестве дополнительной, просто обычную строку ...
  • 0
    Скорее всего, он должен проверить, содержит ли строка хотя бы один символ и поменял ли он два параметра
Показать ещё 1 комментарий
15

Вот две функции, которые не вводят временную строку, которая может быть полезна, когда иглы существенно большие:

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

function endsWith($haystack, $needle)
{
    return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
  • 2
    +1 Работает с PHP5.1 и ИМХО лучший ответ. Но endsWidth должен return $needle==='' || substr_compare( ... поэтому он работает, как и ожидалось, для -strlen($needle)===0 который без исправления заставляет endsWith('a','') возвращать false
  • 0
    @Tino Спасибо ... Я чувствую, что это на самом деле ошибка в substr_compare() , поэтому я добавил PR, чтобы это исправить :)
Показать ещё 2 комментария
15

Я понимаю, что это было закончено, но вы можете посмотреть strncmp, поскольку он позволяет вам поместить длину строки для сравнения, так:

function startsWith($haystack, $needle, $case=true) {
    if ($case)
        return strncasecmp($haystack, $needle, strlen($needle)) == 0;
    else
        return strncmp($haystack, $needle, strlen($needle)) == 0;
}    
  • 0
    как бы вы покончили с этим?
  • 0
    @Mark - вы можете посмотреть на принятый ответ, но я предпочитаю использовать strncmp в основном потому, что считаю его более безопасным.
Показать ещё 2 комментария
13

У этого вопроса уже много ответов, но в некоторых случаях вы можете согласиться на что-то более простое, чем все. Если строка, которую вы ищете, известна (жестко запрограммирована), вы можете использовать регулярные выражения без кавычек и т.д.

Проверьте, начинается ли строка с 'ABC':

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

заканчивается на "ABC":

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

В моем простом случае я хотел проверить, заканчивается ли строка косой чертой:

preg_match('/\/$/', $myPath);   // slash has to be quoted

Преимущество: поскольку он очень короткий и простой, вам не нужно определять функцию (например, endsWith()), как показано выше.

Но опять же - это не решение для каждого случая, просто это очень специфическое.

  • 0
    вам не нужно жестко кодировать строку. регулярное выражение может быть динамическим.
  • 2
    @self верно, но если строка не является жестко закодированной, вы должны ее избежать. В настоящее время есть 2 ответа на этот вопрос, которые делают это. Это легко, но немного усложняет код. Поэтому я хотел сказать, что для очень простых случаев, когда возможно жесткое кодирование, вы можете сделать его простым.
Показать ещё 2 комментария
10

Вы можете использовать strpos и strrpos

$bStartsWith = strpos($sHaystack, $sNeedle) == 0;
$bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle);
  • 1
    Если вы используете тройное равенство здесь strpos($sHaystack, $sNeedle) == 0 как это strpos($sHaystack, $sNeedle) === 0 ? Я вижу ошибку, когда false == 0 оценивается как true .
7

Короткие и понятные однострочные символы без регулярных выражений.

startsWith() прямолинейно.

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

endsWith() использует слегка причудливый и медленный strrev():

function endsWith($haystack, $needle) {
   return (strpos(strrev($haystack), strrev($needle)) === 0);
}
  • 1
    strpos не является "правильным инструментом" .. (и ни strrev)
  • 0
    @FrancescoMM: strpos не "правильный инструмент" ... Почему? Каковы "правильные инструменты" тогда? РЕДАКТИРОВАТЬ: я прочитал ваш ответ ниже. Я думал, что программирование - это как изобретение, использующее ресурсы, которые у вас есть ... Так что нет правильного или неправильного ... только работает или не работает ... производительность вторична.
Показать ещё 1 комментарий
6

Обычно я заканчиваю тем, что в настоящее время с библиотекой, например underscore-php.

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   

Библиотека полна других удобных функций.

6

Сфокусируйтесь на startswith, если вы уверены, что строки не пусты, добавив тест на первый char, перед сравнением, strlen и т.д. немного ускоряет работу:

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

Это как-то (на 20% -30%) быстрее. Добавление другого теста char, например $haystack {1} === $needle {1}, похоже, не ускоряет работу, может даже замедлить работу.

=== кажется быстрее, чем == Условный оператор (a)?b:c кажется быстрее, чем if(a) b; else c;


Для тех, кто спрашивает "почему бы не использовать strpos?" вызов других решений "ненужная работа"


strpos работает быстро, но это не подходящий инструмент для этой работы.

Чтобы понять, вот пример симуляции:

Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c

Что компьютер делает "внутри"?

    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

Предполагая, что strlen не выполняет итерацию всей строки (но даже в этом случае), это совсем не удобно.

  • 0
    Там только ускорение, если первые символы отличаются.
  • 2
    @ Джек, да, конечно, идея в том, что статистически это происходит, поэтому ускорение обычно составляет 20% -30% по всему тестовому набору (включая случаи, когда он не отличается). Вы получаете много, когда они разные, и очень мало, когда нет. В среднем вы получаете 30% (варьируется в зависимости от набора, но в основном вы набираете скорость на больших тестах)
Показать ещё 2 комментария
5

Здесь многобайтная безопасная версия принятого ответа, она отлично работает для строк UTF-8:

function startsWith($haystack, $needle)
{
    $length = mb_substr($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);
}
  • 1
    Я уверен, что это просто трата процессора. Все, что вам нужно проверить, для StarstWith и EndsWith, это просто проверить, что байты совпадают, и это именно то, что делает принятый ответ. эта 1 тратит впустую время, вычисляя количество символов иглы utf8, и где положение n-ого символа utf8 стога сена ... я думаю, не будучи на 100% уверенным, это - просто трата процессора. Можете ли вы придумать реальный тестовый случай, когда принятый ответ не получается, а это не так?
  • 0
    @hanshenrik - это может произойти, между прочим, в очень редком случае, когда вы ищете строку, которая содержит те же байты, что и UTF8, но с отсутствующей половиной последнего символа. Например, у вас есть Unicode C5 91 (буква «ő»), и вы ищете C5 (буква «Å»), он не должен совпадать. С другой стороны, конечно, зачем вам искать в стоге сена utf иглу без утфеля ... Но для пуленепробиваемых проверок это должно считаться возможным.
5

Ответ mpen невероятно тщательный, но, к сожалению, предоставленный эталонный тест имеет очень важный и пагубный надзор.

Поскольку каждый байт в иголках и стогах сена является полностью случайным, вероятность того, что пара игл-сеновалов будет отличаться по самому первому байту, равна 99.609375%, а это значит, что в среднем около 99609 из 100000 пар будут отличаться на очень первый байт. Другими словами, эталон сильно отклоняется к реализациям startswith, которые явно проверяют первый байт, как это делает strncmp_startswith2.

Если вместо этого выполняется тестовый цикл, выполните следующие действия:

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

Результаты тестов показывают немного другую историю:

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

Конечно, этот тест все еще не может быть абсолютно непредвзятым, но он проверяет эффективность алгоритмов, когда они также дают частично соответствующие иголки.

5

Я надеюсь, что приведенный ниже ответ может быть эффективным и простым:

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

:

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

function endsWith($str, $needle){
   $length = strlen($needle);
   return !$length || substr($str, - $length) === $needle;
}
4

Функция substr может возвращать false во многих особых случаях, поэтому вот моя версия, которая касается этих проблем:

function startsWith( $haystack, $needle ){
  return $needle === ''.substr( $haystack, 0, strlen( $needle )); // substr false => empty string
}

function endsWith( $haystack, $needle ){
  $len = strlen( $needle );
  return $needle === ''.substr( $haystack, -$len, $len ); // ! len=0
}

Тесты (true означает "хорошо" ):

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

Кроме того, функция substr_compare также стоит посмотреть. http://www.php.net/manual/en/function.substr-compare.php

3

Я бы сделал это так:

     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;
        }
  • 0
    Забыв вернуть false, если он не совпадает. Ошибка неправильная, так как возвращаемое значение функции не следует «предполагать», но я знаю, что вы собираетесь делать, по крайней мере, по сравнению с другими ответами.
3

Это может работать

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

Источник: https://stackoverflow.com/questions/4419644/check-if-variable-starts-with-http

3

Почему не следующее?

//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 . "!";
}

Вывод:

Найдено значение в начале значенияhaystack!

Имейте в виду, что strpos вернет false, если игла не была найдена в стоге сена, и вернет 0, если и только если игла была найдена с индексом 0 (AKA начало).

И здесь endWith:

$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 . "!";
}

В этом случае нет необходимости в функции startsWith() как

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

вернет true или false точно.

Кажется странным, что это просто, потому что все дикие функции работают без изменений.

  • 3
    Кажется странным, что если вы ищете «xy» внутри строки «abcdefghijklmxyz» вместо того, чтобы просто сравнивать «x» с «a» и возвращать FALSE, вы просматриваете каждый символ от «a» до «m», а затем в конечном итоге находите «xy» внутри строки, и, наконец, вы возвращаете FALSE, потому что его позиция не равна нулю! Это то, что вы делаете, и это странно и дико, чем любая другая безудержная функция здесь.
  • 0
    Простота в наборе, а не в логике.
Показать ещё 2 комментария
2

Просто рекомендация:

function startsWith($haystack,$needle) {
    if($needle==="") return true;
    if($haystack[0]<>$needle[0]) return false;
    if(substr_compare($haystack,$needle,0,strlen($needle))==0) return true;
    return false;
}

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

  • 1
    Ошибка в вашем коде: startsWith("123", "0") дает true
  • 0
    Да, плохо! Произошла проверка. Сожалею! (Просто хотел проиллюстрировать концепцию в строке 3)
2

Вы также можете использовать регулярные выражения:

function endsWith($haystack, $needle, $case=true) {
  return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
  • 3
    $ needle должен быть экранирован с помощью preg_quote($needle, '/') .
2

Основываясь на ответе Джеймса Блэка, вот его концы с версией:

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

}

Примечание. Я поменял часть if-else на функцию James Black startsWith, потому что strncasecmp - это фактически нечувствительная к регистру версия strncmp.

  • 2
    Обратите внимание, что strrev() является креативным, но очень дорогостоящим, особенно если у вас есть, скажем, строки ... 100Kb.
  • 0
    Используйте === вместо == чтобы быть уверенным. 0 равно многим вещам в PHP.
1

Многие из предыдущих ответов будут работать так же хорошо. Однако это возможно так коротко, как вы можете это сделать, и делать то, что вам нужно. Вы просто заявляете, что хотите, чтобы он вернул true. Поэтому я включил решения, которые возвращают логическое значение true/false и текстовое значение true/false.

// 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';
}
  • 1
    не работает с $needle==='0'
  • 0
    Правда. Тем не менее, Питер просил функцию, которая будет работать со строками символов. Тем не менее, я обновил свой ответ, чтобы успокоить вас.
Показать ещё 2 комментария
1

Это эффективное решение для PHP 4. Вы можете получить более быстрые результаты, если на PHP 5 с помощью substr_compare вместо 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;
}
0

Самые быстрые концыWith():

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

Ориентир:

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

Результаты тестов:

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
  • 3
    +1 за то, что вы нашли время, чтобы сравнить различные решения и сравнить их! Вы должны также упомянуть, какую версию PHP вы использовали, так как оптимизация выполняется по мере развития языка! Я видел значительные улучшения в функциях сравнения строк из одной версии PHP в другую :)
  • 1
    повторение @ChristopheDeliens и его просьба предоставить версию PHP. Я запустил ваш тест на 7.3.2 и получил аналогичные результаты FWIW.
0
$ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot
  • 3
    Согласно документации, strrchr () вернет строку из последнего вхождения '.' до конца, что означает, что ваш $ end_with будет истинным, если '.' где-нибудь в $ text. Следовательно, они должны быть следующими: ('.' === strrchr ($ text, '.'))
  • 4
    Поскольку ваш ответ неверен и не соответствует заявленным требованиям, а вы отказываетесь принять мои изменения, чтобы исправить ваш ответ, я отклоняю этот ответ, поскольку он «опасно неправильный».
-1

Не знаю, почему это так сложно для людей. Substr делает отличную работу и эффективен, так как вам не нужно искать всю строку, если она не соответствует.

Кроме того, поскольку я не проверяю целочисленные значения, но сравнивая строки, мне не обязательно обязательно беспокоиться о строгом случае ===. Тем не менее, === хорошая привычка вступать.

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

или даже лучше оптимизирован.

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

function endsWith($haystack,$needle) {
  return substring($haystack,-strlen($needle)) == $needle);
}
  • 1
    Что отличается или новое в вашем ответе по сравнению с ответом MrHus?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню