30 Вопрос: функции functionsWith () и окончание () в PHP

вопрос создан в Sat, Feb 3, 2018 12:00 AM

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

Например:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
    
1350
  1. См. класс Str начинается с () и заканчивается с () для хорошо проверенные методы. Крайние случаи были обнаружены, поэтому широкое использование этого кода является преимуществом.
    2014-12-06 23: 32: 04Z
  2. Вы можете найти s($str)->startsWith('|') и s($str)->endsWith('}') полезно, как указано в этой автономной библиотеке .
    2016-07-26 23: 46: 47Z
  3. Предупреждение: большинство ответов здесь ненадежны в многобайтовых кодировках, таких как UTF-8.
    2017-05-15 14: 07: 31Z
  4. Следуя моим комментариям выше, вы можете использовать последнюю версию (на сегодняшний день 5.4 ). Примечательно, что launchWith () был оптимизирован для больших строк сена.
    2017-05-22 18: 51: 11Z
  5. 30 ответов                              30                         
    function startsWith($haystack, $needle)
    {
         $length = strlen($needle);
         return (substr($haystack, 0, $length) === $needle);
    }
    
    function endsWith($haystack, $needle)
    {
        $length = strlen($needle);
        if ($length == 0) {
            return true;
        }
    
        return (substr($haystack, -$length) === $needle);
    }
    

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

        
    1451
    2018-08-17 13: 51: 41Z
    1. + 1 Это чище, чем принятый ответ. Кроме того, $length не требуется в последней строке endsWith().
      2009-09-17 02: 57: 33Z
    2. Я бы сказал, чтоndsWith ('foo', '') == false - это правильное поведение. Потому что foo не заканчивается ничем. «Foo» оканчивается на «o», «oo» и «Foo».
      2012-04-13 13: 34: 58Z
    3. EndsWith можно записать намного короче: return substr($haystack, -strlen($needle))===$needle;
      2012-06-11 09: 57: 45Z
    4. Вы можете полностью избежать if, передав в качестве третьего параметра $length в качестве третьего параметра substr: return (substr($haystack, -$length, $length);: это обрабатывает 0600350350505050505050 для всех без исключения.
      2015-01-23 01: 21: 18Z
    5. @ MrHus Я бы порекомендовал использовать многобайтовые безопасные функции, например, mb_strlen и mb_substr
      2016-04-25 08: 49: 28Z

    Вы можете использовать $length == 0 для проверки начала и конца:

    $haystack

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

        
    967
    2019-04-24 08: 24: 09Z
    1. Этот ответ попал в Daily WTF! : D См. thedailywtf.com/articles/…
      2016-04-21 11: 36: 45Z
    2. Обратите внимание, что комментарии @DavidWallace и @FrancescoMM применяются к более старой версии этого ответа. В текущем ответе используется
      function startsWith($haystack, $needle) {
          return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
      }
      function endsWith($haystack, $needle) {
          return substr_compare($haystack, $needle, -strlen($needle)) === 0;
      }
      
      , который (должен) немедленно завершиться неудачей, если игла не соответствует началу стога сена.
      2016-04-21 14: 00: 30Z
    3. Я не понимаю. На основе php.net/manual/en/function.strrpos.php : «Если значение отрицательное, поиск будет начинаться с такого количества символов, начиная с конца строки, с обратным поиском». Кажется, это указывает на то, что мы начинаем с символа 0 (из-за strncmp) и ищем оттуда назад ? Разве это не значит, что вы ничего не ищете? Я также не понимаю strrpos части этого. Я предполагаю, что это опирается на причуду PHP, где некоторые значения являются «правдивыми», а другие «ложными», но как это работает в этом случае?
      2016-04-21 14: 44: 10Z
    4. @ Welbog: например, haystack = -strlength($haystack) needle = !== false и с использованием xxxyyy и поиск начинается с первого yyy. Вместо этого у нас не найдено совпадение (вместо этого мы не нашли x (не найдено совпадение x (вместо совпадения x) of y) и мы больше не можем идти назад (мы находимся в начале строки), поиск завершается немедленно . При использовании strrpos - x в вышеприведенном примере будет возвращаться 0 или false, а не другое значение. Аналогично, !== false в вышеприведенном примере может возвращать strrpos (ожидаемая позиция) или false. Для согласованности я использовал strpos, но вы можете использовать $temp и !== false в функциях соответственно.
      2016-04-21 15: 01: 15Z
    5. @ spoo уже было установлено, что strpos === 0 - ужасное решение, если стог сена велик, а иголка не существует.
      2016-10-08 06: 22: 13Z

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

    Функции

    === 0

    Испытания

    === $temp

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

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

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

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

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

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

    launchwith_benchmark.php

        
    231
    2017-06-28 19: 46: 38Z
    1. Если строки не пусты, как в ваших тестах, это на самом деле как-то (на 20-30%) быстрее:
      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
      
      Я добавил ответ ниже.
      2013-07-28 15: 38: 33Z
    2. @ Jronny, потому что 110 меньше 133 ... ??
      2014-12-02 16: 41: 15Z
    3. Черт, я не знаю, что пришло мне в голову в то время. Чрезвычайно недосыпание.
      2014-12-18 03: 08: 02Z
    4. @ mpen, я вообще не заметил слона: (
      2017-11-21 02: 15: 28Z
    5. Эти тесты не годятся для тестирования производительности. То, что вы делаете, использует случайную строку в качестве иглы. В 99,99% случаев НЕТ совпадений. Большинство функций завершится после сопоставления первого байта. А как насчет случаев, когда совпадение найдено? Какая функция занимает меньше времени, чтобы завершить успешное совпадение? Как насчет случаев, когда 99% иглы совпадают, но не последние несколько байтов? Какая функция занимает наименьшее количество времени, чтобы завершить сопоставление?
      2017-12-15 15: 06: 33Z

    Все ответы до сих пор, по-видимому, выполняют множество ненужной работы,

    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
    
    , function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;} и т. д. Функции strlen calculations и string allocations (substr) возвращают индекс первого вхождения 'strpos'/06005050/06005050/06005050/06005050: 0> 0050> 'stripos'     
    133
    2015-08-04 15: 13: 13Z
    1. $needle функция содержит ошибку. Его первая строка должна быть (без -1): $haystack
      2010-08-05 17: 16: 43Z
    2. Функция strlen () не является ненужной. Если строка не начинается с указанной иглы, тогда ваш код будет без необходимости сканировать весь стог сена.
      2011-01-04 15: 46: 55Z
    3. @ Отметьте, да, проверка только начала - НАМНОГО быстрее, особенно если вы делаете что-то вроде проверки типов MIME (или любого другого места, где строка связана с быть большим)
      2011-09-26 15: 39: 56Z
    4. @ mark Я провел несколько тестов с 1000-стакановым стогом сена и 10 или 800-символьной иглой, и strpos был на 30% быстрее. Сделайте свои тесты, прежде чем утверждать, что что-то быстрее или нет ...
      2012-08-06 00: 39: 37Z
    5. Настоятельно рекомендуется заключить в кавычку стрелку, например,
      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;
      }
      
      , если есть любой шанс, что это уже не строка (например, если она идет от endsWith()). В противном случае поведение [нечетное] по умолчанию $expectedPosition = strlen($haystack) - strlen($needle); может привести к неожиданным результатам: " Если игла не является строкой, она преобразуется в целое число и применяется как порядковый номер символа. "
      2012-12-03 03: 47: 43Z
    46
    2013-08-01 15: 46: 22Z
    1. strtolower - не лучший способ создания нечувствительных к регистру функций. В некоторых регионах корпус является более сложным, чем просто верхний и нижний.
      2009-05-13 21: 25: 33Z
    2. Я вижу жалобы, но нет решения ... Если вы хотите сказать, что это плохо, то вам следует привести пример того, как это должно быть.
      2009-05-14 11: 06: 48Z
    3. @ WebDevHobo: поэтому я сам добавил ответ за день до вашего комментария. Для вашего кода strcasecmp был действительно правильным решением.
      2010-08-06 07: 34: 55Z

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

    json_decode()     
    28
    2012-11-16 15: 14: 59Z
    1. в php для строковых операций упорядочение параметров составляет $haystack, $needle. эти функции обращены назад и действуют как функции массива, где порядок на самом деле равен $needle, $haystack.
      2014-12-02 01: 59: 39Z

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

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

    strpos()

    оканчивается на 'ABC':

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

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

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

    Преимущество: поскольку оно очень короткое и простое, вам не нужно определять функцию (например,

    preg_match('/^ABC/', $myString); // "^" here means beginning of string
    
    ), как показано выше.

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

        
    23
    2018-10-30 19: 55: 17Z
    1. вам не нужно жестко кодировать строку. регулярное выражение может быть динамическим.
      2016-05-15 03: 02: 42Z
    2. @ self true, но если строка не является жестко закодированной, вы должны ее избежать. В настоящее время есть 2 ответа на этот вопрос, которые делают это. Это легко, но немного усложняет код. Поэтому я хотел сказать, что для очень простых случаев, когда возможно жесткое кодирование, вы можете сделать его простым.
      2016-05-15 19: 13: 07Z
    3. Вы также не должны экранировать косую черту, вы можете заключить регулярное выражение в какой-либо другой символ, например
      preg_match('/ABC$/', $myString); // "$" here means end of string
      
      , так что косая черта (
      preg_match('#/$#', $myPath);   // Use "#" as delimiter instead of escaping slash
      
      ) не должна быть убежали. См. Пример № 3 здесь: php.net/manual/en/function.preg- match.php .
      2018-10-24 13: 16: 28Z
    4. Спасибо @cjbarth. Изменил мой ответ соответственно. Кстати, «#» - это пример, приведенный в php.net/manual/en/regexp.reference.delimiters.php при работе с косой чертой.
      2018-10-30 19: 57: 03Z

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

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

    endsWith()     
    22
    2009-12-15 08: 53: 34Z
    1. это, вероятно, самый эффективный ответ, потому что не использует какую-либо функцию в качестве дополнительной,просто обычная строка ...
      2013-08-01 10: 29: 21Z
    2. Вероятно, он должен проверить, содержит ли строка хотя бы один символ и поменял ли он два параметра
      2018-05-15 14: 51: 29Z
    3. Объявление. Иглы, которые содержат стога сена. Кстати, есть некоторые ужасные убытки с: @, но результат правильный
      2018-07-20 11: 28: 16Z

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

    /     
    17
    2014-02-21 02: 56: 12Z
    1. + 1 Работает с PHP5.1 и IMHO лучший ответ. Но
      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
      
      должен делать endsWithChar('','x') ... поэтому он работает, как и ожидалось, для
      function startsWith($haystack, $needle)
      {
          return strncmp($haystack, $needle, strlen($needle)) === 0;
      }
      
      function endsWith($haystack, $needle)
      {
          return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
      }
      
      , который без исправления возвращает endsWidth return $needle==='' || substr_compare(
      2014-02-20 21: 53: 00Z
    2. @ Tino Спасибо ... Я чувствую, что это действительно ошибка в -strlen($needle)===0, поэтому я добавил PR чтобы это исправить:)
      2014-02-21 02: 55: 56Z
    3. Вызов endsWith('a','') вызывает предупреждение: «substr_compare (): начальная позиция не может превышать начальную длину строки». Может быть, это еще одна ошибка в false, но чтобы ее избежать, вам необходима предварительная проверка, например ... substr_compare() ... endsWith('', 'foo')
      2015-08-09 19: 47: 18Z
    4. @ gx_ Нет необходимости замедлять работу с большим количеством кода. Просто используйте substr_compare() .. чтобы подавить это предупреждение.
      2018-07-20 11: 35: 16Z

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

    || (strlen($needle) <= strlen($haystack) && substr_compare(     
    16
    2009-09-17 02: 50: 51Z
    1. как бы вы покончили с этим?
      2011-08-26 15: 20: 33Z
    2. @ Марк - вы можете посмотреть на принятый ответ, но я предпочитаю использовать strncmp в основном потому, что я считаю, что это безопаснее.
      2011-08-26 16: 45: 48Z
    3. Я имею в виду именно с strncmp. Вы не можете указать смещение. Это будет означать, что вашей функции EndWith придется полностью использовать другой метод.
      2011-08-26 18: 50: 26Z
    4. @ Mark - для целей, с которыми я просто использовал бы strrpos ( php.net/manual/en/function.strrpos.php ), но, как правило, каждый раз, когда вы используете strcmp, strncmp, вероятно, является более безопасным вариантом.
      2011-08-27 00: 15: 34Z

    Быстрое решение endWith ():

    ) === 0);

    Benchmark:

    return $needle === '' || @substr_compare(

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

    function startsWith($haystack, $needle, $case=true) {
        if ($case)
            return strncasecmp($haystack, $needle, strlen($needle)) == 0;
        else
            return strncmp($haystack, $needle, strlen($needle)) == 0;
    }    
    
        
    12
    2018-07-24 06: 29: 41Z
    1. + 1 за то, что вы потратили время на сравнение различных решений и их сравнение! Вы должны также упомянуть, какую версию PHP вы использовали, так как оптимизация выполняется по мере развития языка! Я видел значительные улучшения в функциях сравнения строк из одной версии PHP в другую:)
      2018-10-03 13: 51: 06Z
    2. повторяет @ChristopheDeliens и его запрос предоставить версию PHP. Я запустил ваш тест на 7.3.2 и получил аналогичные результаты FWIW.
      2019-02-19 21: 50: 08Z

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

    # 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
    
        
    11
    2016-07-29 07: 11: 16Z
    1. Если вы используете здесь тройное равенство strpos как этот strrpos? Я вижу ошибку, когда
      $bStartsWith = strpos($sHaystack, $sNeedle) == 0;
      $bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle);
      
      оценивается как strpos($sHaystack, $sNeedle) == 0.
      2017-06-23 14: 37: 58Z

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

    начинается с () прямо вперед.

    strpos($sHaystack, $sNeedle) === 0

    endWith () использует слегка причудливую и медленную функцию strrev ():

    false == 0     
    8
    2011-06-28 22: 40: 33Z
    1. strpos не является "правильным инструментом" .. (и ни strrev)
      2013-07-28 14: 19: 43Z
    2. @ FrancescoMM: strpos не является "правильным инструментом" ... Почему? Каковы "правильные инструменты" тогда? РЕДАКТИРОВАТЬ. Я прочитал ваш ответ ниже. Я думал, что программирование - это как изобретение, использующее ресурсы, которые у вас есть .. Так что нет правильного или неправильного ... только работает или не работает ... производительность вторична.
      2018-03-24 08: 22: 20Z
    3. "потому что это инструмент для поиска, а не для сравнения?" Соч. Aristoteles
      2018-03-24 08: 42: 43Z

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

    true     
    8
    2019-04-17 17: 08: 38Z
    1. я почти уверен, что это пустая трата процессора. Все, что вам нужно проверить, для StarstWith и EndsWith, это просто проверить, что байты совпадают, и это именно то, что делает принятый ответ. эта 1 тратит впустую время, вычисляя количество символов иглы utf8, и где положение n-го символа utf8 стога сена ... я думаю, не будучи уверенным на 100%, это просто пустая трата процессора. Можете ли вы придумать реальный тестовый случай, когда принятый ответ не получается, а это не так?
      2018-05-12 00: 06: 42Z
    2. @ hanshenrik - это может произойти, кстати, в очень редком случае, когда вы ищете строку, которая содержит те же байты, что и UTF8, но при этом отсутствует половина последнего символа. Например, у вас есть Unicode C5 91 (буква «ő»), и вы ищете C5 (буква «Å»), он не должен совпадать. С другой стороны, конечно, зачем вам искать в стоге сена utf иглу не-utf ... Но для пуленепробиваемых проверок это должно считаться возможным.
      2018-09-08 10: 43: 11Z
    3. В
      function startsWith($haystack, $needle) {
         return (strpos($haystack, $needle) === 0);
      }
      
      это должно быть
      function endsWith($haystack, $needle) {
         return (strpos(strrev($haystack), strrev($needle)) === 0);
      }
      
      2019-04-16 16: 02: 05Z
    4. @ ThomasKekeisen Спасибо, исправили.
      2019-04-17 17: 08: 51Z

    Сосредоточение внимания на запуске начинается, если вы уверены, что строки не пусты, добавление теста для первого символа, перед сравнением, strlen и т. д. немного ускоряет процесс:

    function startsWith($haystack, $needle)
    {
        $length = mb_strlen($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);
    }
    

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

    startsWith кажется быстрее, чем $length = mb_strlen($needle, 'UTF-8'); Условный оператор

    function startswith5b($haystack, $needle) {
        return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
    }
    
    кажется быстрее, чем ===

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

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

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

    ==

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

    (a)?b:c

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

        
    7
    2013-07-28 15: 34: 42Z
    1. Ускорение происходит только в том случае, если первые символы отличаются.
      2013-08-02 07: 51: 43Z
    2. @ Джек да, конечно, идея в том, что статистически это происходит, поэтому ускорение обычно составляет 20% -30% по всему тестовому набору (включая случаи, когда это не отличается). Вы получаете много, когда они разные, и очень мало, когда нет. В среднем вы получаете 30% (варьируется в зависимости от набора, но в основном вы набираете скорость при больших тестах)
      2013-09-18 08: 42: 15Z
    3. ", но это не подходящий инструмент для этой работы" ... Любая цитата?
      2018-03-24 08: 29: 05Z
    4. WTF. Я перечислил весь процесс ниже, кого я должен процитировать, более того? Будете ли вы использовать функцию, которая ищет до конца строки, чтобы сказать вам, что символ кулак не является «а»? Делай, кого это волнует? Это не правильный инструмент, потому что это инструмент для поиска, а не для сравнения, нет необходимости цитировать Аристотеля, чтобы утверждать очевидное!
      2018-03-24 08: 40: 19Z

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

    if(a) b; else c;     
    6
    2013-10-18 13: 01: 23Z

    Я обычно заканчиваю тем, что хожу с библиотекой вроде underscore-php в эти дни.

    Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c
    

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

        
    6
    2015-01-23 03: 53: 12Z

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

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

        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
    
    , которые явно проверяют первый байт, как это делает
    $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';
    
    .

    Если цикл генерации тестов реализован следующим образом:

    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   
    

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

    startswith

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

        
    6
    2016-09-21 14: 31: 07Z

    Функция 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
    

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

    false

    Также стоит обратить внимание на функцию

    function startsWith( $haystack, $needle ){
      return $needle === ''.substr( $haystack, 0, strlen( $needle )); // substr's false => empty string
    }
    
    function endsWith( $haystack, $needle ){
      $len = strlen( $needle );
      return $needle === ''.substr( $haystack, -$len, $len ); // ! len=0
    }
    
    . http://www.php.net/manual/en/function. зиЬзЬг-compare.php р>     
    4
    2012-02-21 11: 52: 55Z

    короче:

    true     
    4
    2012-04-19 21: 39: 24Z

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

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

    Источник: https://stackoverflow.com/a/4419658

        
    4
    2017-05-23 12: 10: 48Z

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

    substr_compare

    Вывод:

      

    Найденное значение в начале стоимостного стека!

    Имейте в виду, что

    function startsWith($str, $needle){
       return substr($str, 0, strlen($needle)) === $needle;
    }
    
    function endsWith($str, $needle){
       $length = strlen($needle);
       return !$length || substr($str, - $length) === $needle;
    }
    
    вернет false, если игла не была найдена в стоге сена, и вернет 0, если и только если игла была найдена с индексом 0 (AKA начало).

    А вот и концы с

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

    В этом сценарии нет необходимости в функции launchWith (), так как

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

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

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

        
    4
    2014-04-12 19: 17: 53Z
    1. Кажется странным, что если вы ищете "xy" внутри строки "abcdefghijklmxyz" вместо простого сравнения "x" с "a" и возврата FALSE, вы смотрите каждый символ от "a" до "m", затем вы найдете "xy" внутри строки, и, наконец, вы вернете FALSE, потому что его позиция не равна нулю! Это то, что вы делаете, и это странно и дико, чем любая другая безудержная функция здесь.
      2014-01-23 15: 05: 28Z
    2. Простота заключается в наборе текста, а не в логике.
      2014-01-23 17: 34: 44Z
    3. Это не столько логика, сколько возможная оптимизация, на которую указывал Франко. Использование strpos будет медленным, за исключением случаев, когда оно совпадает.
      $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 . "!";
      }
      
      будет намного лучше в этом случае.
      2014-07-02 00: 33: 26Z
    4. Когда вы выполняете такие низкоуровневые функции, вы, как правило, хотите выбрать наиболее оптимизированное по скорости решение, независимо от его сложности, так как это будет называться миллионами раз. Каждая микросекунда, которую вы получаете или теряете, будет иметь реальное значение. Так что лучше избавиться от этого (а затем забыть о сложности, теперь, когда у вас есть функция), вместо того, чтобы искать внешний вид и потерять ужасное количество времени спустя, когда вы даже не знаете, что пошло не так. Представьте, что вы проверяете строку размером 2 ГБ, которая не совпадает.
      2018-09-03 13: 09: 17Z

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

    (strpos($stringToSearch, $doesItStartWithThis) === 0)
    
        
    4
    2014-10-07 13: 27: 04Z
    1. Забывает возвращать false, если он не совпадает. Ошибка неправильная, так как возвращаемое значение функции не должно быть «предположено», но я знаю, что вы собираетесь, по крайней мере, по сравнению с другими ответами.
      2016-10-07 19: 58: 19Z

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

    strpos()

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

        
    4
    2019-05-02 10: 27: 49Z
    1. Ошибка в вашем коде: strncmp() приводит к
           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;
              }
      
      2018-07-20 11: 10: 11Z
    2. Да, плохо! Произошла проверка. Сожалею! (Просто хотел проиллюстрировать концепцию в строке 3)
      2018-07-20 14: 43: 24Z

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

    function startsWith($haystack,$needle) {
        if($needle==="") return true;
        if($haystack[0]<>$needle[0]) return false; // ------------------------- speed boost!
        return (0===substr_compare($haystack,$needle,0,strlen($needle)));
    }
    
        
    3
    2010-12-22 14: 40: 13Z
    1. $needle должен быть экранирован с startsWith("123", "0").
      2012-11-16 15: 10: 44Z

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

    true     
    3
    2014-10-27 13: 03: 05Z
    1. не работает с
      function endsWith($haystack, $needle, $case=true) {
        return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
      }
      
      2014-02-2021: 31: 32Z
    2. Истина. Однако Питер запрашивал функцию, которая бы работала со строками символов. Тем не менее, я обновил свой ответ, чтобы успокоить вас.
      2014-10-23 21: 02: 56Z
    3. После редактирования ваше решение теперь полностью устарело. Он возвращает preg_quote($needle, '/') и
      // 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';
      }
      
      в виде строк, которые оба являются $needle==='0' в логическом смысле. Это хороший шаблон для чего-то вроде underhanded.xcott.com хотя;)
      2014-10-26 11: 08: 17Z
    4. Ну, Питер только что заявил, что хочет, чтобы он возвратил 'true'. Так что я решил вернуть то, что он просил. Я добавил обе версии, на случай, если это не то, что он хотел.
      2014-10-27 13: 04: 39Z

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

    'true'

    Примечание: я поменял часть if-else на функцию JamesW BlackSamsarsWith, потому что strncasecmp - это на самом деле версия strncmp без учета регистра.

        
    2
    2009-10-30 00: 17: 34Z
    1. Обратите внимание, что 'false' является креативным , но очень дорогостоящим, особенно если у вас есть строки, скажем ... 100Kb.
      2014-06-25 02: 45: 54Z
    2. Для уверенности используйте true вместо
      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);
      
      }
      
      . strrev() равнозначен многим вещам в PHP.
      2016-01-29 11: 38: 58Z

    Вот эффективное решение для PHP 4. Вы можете получить более быстрые результаты, если на PHP 5, используя === вместо ==.

    0     
    1
    2015-03-21 02: 06: 29Z
    substr_compare     
    - 1
    2017-11-04 17: 08: 41Z
    1. Согласно документам strrchr () вернет строку из последнего вхождения '.' до конца, что означает, что ваш $конец_с будет истинным, если '.' находится в любом месте в $text. Следовательно, имя_конца должно быть: ('.' === strrchr ($text, '.'))
      2016-07-05 13: 20: 04Z
    2. Так как ваш ответ неверен и не выполняет то, что он требует, и вы отказываетесь принять мое изменение, чтобы исправить свой ответ, я отклоняю этот ответ как есть " опасно неверно ".
      2017-03-25 17: 33: 37Z

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

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

    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;
    }
    
        
    - 3
    2016-10-07 19: 55: 02Z
    1. Что нового или нового в вашем ответе по сравнению с ответом MrHus?
      2016-10-08 06: 33: 42Z
    $ends_with = strrchr($text, '.'); // Ends with dot
    $start_with = (0 === strpos($text, '.')); // Starts with dot
    
источник размещен Вот