Функции startWith () и endWith () в PHP

avatar
Ali
7 мая 2009 в 12:14
916012
34
1605

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

Например:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
Источник
Gras Double
6 декабря 2014 в 23:32
23

Смотрите Laravel Str class startWith () и endWith () для хорошо протестированных методов. Были обнаружены крайние случаи, поэтому широкое использование этого кода является преимуществом.

caw
26 июля 2016 в 23:46
1

Вы можете найти s($str)->startsWith('|') и s($str)->endsWith('}') полезными, как показано в этой автономной библиотеке.

Álvaro González
15 мая 2017 в 14:07
4

Предупреждение: большинство ответов здесь ненадежны в многобайтовых кодировках, таких как UTF-8.

Gras Double
22 мая 2017 в 18:51
0

Следуя моему вышеупомянутому комментарию, вы можете использовать последнюю версию (на сегодняшний день 5.4). Примечательно, что startWith () оптимизирован для больших строк стога сена.

Jsowa
1 октября 2020 в 17:06
5

В PHP 8.0 представлены новые методы для этого задания str_starts_with и str_end_with: coderhelper.com/a/64160081/7082164

Ответы (34)

avatar
MrHus
7 мая 2009 в 12:24
1747

PHP 8.0 и выше

Начиная с PHP 8.0 вы можете использовать функции str_starts_with и str_ends_with.

echo str_starts_with($str, '|');

PHP до версии 8.0

function startsWith( $haystack, $needle ) {
     $length = strlen( $needle );
     return substr( $haystack, 0, $length ) === $needle;
}
function endsWith( $haystack, $needle ) {
    $length = strlen( $needle );
    if( !$length ) {
        return true;
    }
    return substr( $haystack, -$length ) === $needle;
}
timoxley
1 февраля 2011 в 01:33
0

имена переменных неясны. например, char - это строка, а не один символ. Возможно, рассмотрите возможность переименования параметров в обычные php $ haystack и $ Need.

AgentConundrum
7 февраля 2011 в 18:11
5

К вашему сведению, параметр $ length в endsWith() является избыточным, поскольку substr() в любом случае завершится в конце строки.

MrHus
13 апреля 2012 в 13:34
18

Я бы сказал, что endWith ('foo', '') == false - правильное поведение. Потому что foo ничем не заканчивается. «Foo» оканчивается на «o», «oo» и «Foo».

Micha Roon
2 мая 2012 в 06:18
0

спасибо, я нашел это обозначение более кратким substr ($ haystack, - strlen ($ Need)) Нет необходимости в $ start и * -1

Rok Kralj
11 июня 2012 в 09:57
137

EndsWith можно написать намного короче: return substr($haystack, -strlen($needle))===$needle;

ruX
21 июля 2012 в 17:51
1

startWith не работает с аргументами ("100", "100"), изменение равно == решить проблему

wdev
6 августа 2012 в 00:40
1

для startWith strpos быстрее, чем substr.

Benj
29 ноября 2012 в 15:15
0

Я искал простой способ тестирования: строка начинается с любого набора строк, например strStartsWith (array (allStarts)). Я опубликовал то, что сделал, ниже, надеясь, что кому-то это пригодится. Я очень удивлен, что разработчики PHP не реализовали эти функции, поскольку они очень полезны каждый день.

FrancescoMM
28 июля 2013 в 14:44
0

Тестирование на $haystack{0}===$needle{0} раньше немного ускоряет работу, если $ Need и $ haystack не пусты (см. Ответ). Если вы повторно используете одну и ту же $ Need, сохраните ее длину, не нужно каждый раз использовать strlen (), добавьте параметр $ length в startWith (...). Любая имеющаяся у вас информация о струнах помогает.

Ja͢ck
21 февраля 2014 в 03:01
8

@RokKralj Но только если $needle не пуст.

Besnik
11 октября 2014 в 21:17
0

использовал его в своем строковом классе, потому что он не использует регулярное выражение :-) github.com/bes89/string

mxxk
23 января 2015 в 01:21
12

Вы можете полностью избежать if, передав $length в качестве третьего параметра в substr: return (substr($haystack, -$length, $length);. Это обрабатывает случай $length == 0, возвращая пустую строку, а не весь $haystack.

D.Tate
5 июня 2015 в 18:47
0

Привет, @MrHus, не возражаешь, если я использую твои функции в этом посте без указания авторства?

MrHus
8 июня 2015 в 10:00
2

@ D.Tate Если бы я не хотел, чтобы люди использовали его, я бы не публиковал его в coderhelper. Так что авторство не требуется.

redolent
3 июля 2015 в 22:53
2

Намного более читабельный, чем другой; это решение легче исправить.

Loupax
18 апреля 2016 в 08:30
3

5 строк кода, 5 предложений по улучшению. 500 строк кода, и все говорят: «Ммм, мне нравится»

Pieter B
22 апреля 2016 в 08:25
5

@Loupax, это хорошо. Люди могут понять 5 строк кода и рассуждать об этом. Когда это 500 строк, это слишком много для понимания. Вот почему вам следует писать короткие функции.

19Gerhard85
25 апреля 2016 в 08:49
22

@MrHus Я бы рекомендовал использовать многобайтовые безопасные функции, например mb_strlen и mb_substr

Taufik Nurrohman
7 мая 2017 в 13:35
2

Кстати, а что не так с $startsWith = strpos($str, '|') === 0; $endsWith = substr($str, -1) === '}';?

devios1
5 сентября 2017 в 18:22
1

@RokKralj Я не согласен. Все строки неявно начинаются и заканчиваются пустой строкой. То есть последние 0 символов строки соответствуют пустой строке, как и первые 0 символов. Почему n = 0 обрабатывается иначе, чем n = 1,2,…?

Rok Kralj
10 сентября 2017 в 08:05
0

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

Mike Shiyan
19 декабря 2017 в 11:26
3

@ 19Gerhard85 вам не нужно беспокоиться о многобайтах при сравнении байтов с байтами. Для этого подходят простые функции substr () и strlen ().

Mike Shiyan
19 декабря 2017 в 11:27
0

@MrHus, почему бы просто не использовать strpos () в startWith ()?

Piskvor left the building
23 марта 2018 в 12:32
0

@MikeShiyan: До сих пор никто не упоминал байты, это все символы. При сравнении байтов «ü»! = «Ü» - один - это «СТРОЧНАЯ ЛАТИНСКАЯ БУКВА U С ДИАРЕЗИСОМ», другой - «СТРОЧНАЯ ЛАТИНСКАЯ БУКВА U», за которой следует «КОМБИНИРОВАННЫЙ ДИАРЕЗ». Совершенно разные байты, разная длина байта (!), Но оба одинаковые, один символ . Наверняка вы прочитали joelonsoftware.com/2003/10/08/…

Mike Shiyan
23 марта 2018 в 14:52
0

@Piskvor, значит, в ответе сравниваются символы, а не байты? Я думаю, что это неправда - я полагаю, что strlen() и substr() являются двоично-безопасными функциями. А также strpos(). Поэтому я просто не понимаю, почему в ответе используется этот код вместо простого strpos($haystack, $needle) === 0. P.S .: хотя я не читал упомянутую статью, я знаю разницу между символами и байтами, не беспокойтесь об этом.

Piskvor left the building
23 марта 2018 в 14:53
1

Это действительно так: вопрос касается символов, а ответ сравнивает байты.

Rudiger W.
17 июля 2018 в 15:47
0

По крайней мере, для startWith () я не понимаю, зачем нужно это хитрое решение. 1 миллион итераций занимает 1086 мс, strncmp занимает 1017 мс с тем же результатом.

Rubén Ruíz
5 октября 2018 в 21:22
0

Я думаю, что следует добавить «общедоступную статику», чтобы их можно было использовать в качестве ссылочной функции без создания экземпляра, например, if (SomeClassNAME :: startWith ())

ahnbizcad
21 июня 2019 в 22:37
3

тот факт, что нет встроенных функций «начинается с» и «заканчивается», делает php глупым.

JohnnyB
13 февраля 2020 в 19:36
0

было бы полезно добавить strtoupper в $ haystack и $ Need с другим параметром для 'игнорирования'

Gras Double
4 июля 2020 в 03:14
0

Эту функцию startsWith() можно оптимизировать, используя strncmp(): strncmp($haystack, $needle, strlen($needle)) === 0 (ссылки PR 32243 в Laravel). См. Также «Общие подходы пользователя» в этом PHP 8 RFC (указано в ответе Джона).

Gras Double
4 июля 2020 в 04:33
0

Просто не забудьте вернуть true, если игла находится в пустой строке.

avatar
amarinediary
15 марта 2021 в 15:59
5

Обновление от 2021 года, PHP> 8.0

PHP 8.0 представил str_starts_with и str_ends_with.

str_starts_with( string $haystack , string $needle ) : bool
str_ends_with( string $haystack , string $needle ) : bool

В вашем примере у нас будет:

$str = '|apples}';
echo str_starts_with( $str, '|' ); //... true || 1
echo str_ends_with( $str, '}' ); //... true || 1
avatar
Jon
3 июня 2020 в 09:13
49

Обновление PHP 8

PHP 8 включает новые функции str_starts_with и str_ends_with, которые, наконец, обеспечивают эффективное и удобное решение этой проблемы:

$str = "beginningMiddleEnd";
if (str_starts_with($str, "beg")) echo "printed\n";
if (str_starts_with($str, "Beg")) echo "not printed\n";
if (str_ends_with($str, "End")) echo "printed\n";
if (str_ends_with($str, "end")) echo "not printed\n";

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

avatar
ya.teck
3 апреля 2020 в 14:58
0

Для этого можно использовать функцию fnmatch.

// Starts with.
fnmatch('prefix*', $haystack);
// Ends with.
fnmatch('*suffix', $haystack);
hanshenrik
10 мая 2020 в 22:39
2

предупреждение, не бинарный безопасный, и даже не безопасный против игл, содержащих подстановочные знаки =/

avatar
mazatwork
28 августа 2019 в 13:28
3

Без копирования и без внутреннего цикла:

function startsWith(string $string, string $start): bool
{
    return strrpos($string, $start, - strlen($string)) !== false;
}

function endsWith(string $string, string $end): bool
{
    return ($offset = strlen($string) - strlen($end)) >= 0 
    && strpos($string, $end, $offset) !== false;
}
hanshenrik
10 мая 2020 в 22:46
0

это должно быть намного быстрее, чем реализация MrHus! я мог бы сравнить это

avatar
Lucas Bustamante
24 июля 2018 в 06:05
27

Решение для быстрого завершения с ():

# 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
Christophe Deliens
3 октября 2018 в 13:51
4

+1 за то, что нашли время, чтобы сравнить различные решения и протестировать их! вы также должны указать, какую версию PHP вы использовали, поскольку оптимизация выполняется по мере развития языка! Я видел кардинальные улучшения функций сравнения строк от одной версии PHP к другой :)

Jeff
19 февраля 2019 в 21:50
2

повторяя @ChristopheDeliens и его просьбу предоставить версию PHP. Я запустил ваш тест на 7.3.2 и получил аналогичные результаты FWIW.

avatar
Vahid Amiri
10 ноября 2017 в 13:59
16

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

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);
}
hanshenrik
12 мая 2018 в 00:06
3

Я почти уверен, что это просто пустая трата процессора. все, что вам нужно проверить для StarstWith и EndsWith, - это просто проверить совпадение байтов, и это именно то, что делает принятый ответ. это 1 тратит время на вычисление количества символов utf8 на игле, и где позиция n-го символа utf8 стога сена ... я думаю, не будучи на 100% уверенным, это просто трата процессора. Можете ли вы придумать реальный тестовый пример, когда принятый ответ терпит неудачу, а это нет?

dkellner
8 сентября 2018 в 10:43
2

@hanshenrik - это может произойти, кстати, в очень редком случае, когда вы ищете строку, содержащую те же байты, что и UTF8, но с отсутствующей половиной последнего символа. Например, у вас есть код юникода C5 91 (буква «ő»), и вы ищете C5 (буква «Å»), он не должен дать вам совпадения. С другой стороны, конечно, зачем вам искать в стоге сена utf иглу, отличную от utf ... Но для пуленепробиваемых проверок это следует рассматривать как возможность.

Thomas Kekeisen
16 апреля 2019 в 16:02
0

В startsWith это должно быть $length = mb_strlen($needle, 'UTF-8');

Vahid Amiri
17 апреля 2019 в 17:08
2

@ThomasKekeisen Спасибо, исправил.

Jon
30 октября 2020 в 14:32
0

Принятое (в настоящее время принятое) решение уже является многобайтовым. На самом деле он безопасен для двоичного кода, что является еще более надежной гарантией.

avatar
Veeno
21 сентября 2016 в 14:31
7

Ответ 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

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

avatar
dkellner
26 июля 2016 в 20:02
6

Делайте это быстрее:

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

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

ПРИМЕЧАНИЕ: ошибка в комментарии @ Tino ниже уже исправлена ​​

Что касается строк и целых чисел

Если вы хотите принудительно выполнить сравнение строк (то есть вы ожидаете, что startWith ("1234", 12) будет истинным), вам понадобится приведение типов:

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

Я не думаю, что это необходимо, но это интересный крайний случай, приводящий к таким вопросам, как "логическое истина начинается с t?" - так что вы решаете, но убедитесь, что вы решили навсегда.

Tino
20 июля 2018 в 11:10
2

Ошибка в вашем коде: startsWith("123", "0") дает true

dkellner
20 июля 2018 в 14:43
0

Ага, плохо! $ Проверка произошла. Сожалею! (Просто хотел проиллюстрировать концепцию в строке 3)

dkellner
17 декабря 2020 в 08:21
0

@Tino Я бы сказал, что мы могли бы удалить эти 2 комментария прямо сейчас, вы не согласны? То есть, точка взята, это исправлено, и прошло 2 года.

avatar
noamtm
6 января 2016 в 08:59
42

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

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

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

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

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

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

preg_match('#/$#', $myPath);   // Use "#" as delimiter instead of escaping slash

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

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

Ryan
15 мая 2016 в 03:02
0

вам не нужно жестко кодировать строку. регулярное выражение может быть динамическим.

noamtm
15 мая 2016 в 19:13
2

@self true, но если строка не запрограммирована жестко, вы должны ее избежать. На данный момент есть 2 ответа на этот вопрос. Это легко, но немного усложняет код. Я хотел сказать, что для очень простых случаев, когда возможно жесткое кодирование, вы можете оставить его простым.

avatar
ymakux
25 августа 2015 в 17:31
-1
$ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot
Sam Bull
5 июля 2016 в 13:20
5

Согласно документам, strrchr() вернет строку из последнего вхождения '.' до конца, что означает, что ваш $ends_with будет истинным, если '.' находится в любом месте в $text. Следовательно, end_with должен быть: ('.' === strrchr($text, '.'))

Sam Bull
25 марта 2017 в 17:33
6

Поскольку ваш ответ неверен и не соответствует заявленному, и вы отказываетесь принять мое редактирование, чтобы исправить свой ответ, я отрицаю этот ответ, поскольку он «опасно неверен».

avatar
Lex
12 мая 2015 в 12:36
11
Kalyan
23 июня 2017 в 14:37
2

Следует ли использовать здесь тройное равенство strpos($sHaystack, $sNeedle) == 0, например, strpos($sHaystack, $sNeedle) === 0? Я вижу ошибку, когда false == 0 оценивается как true.

avatar
yuvilio
23 января 2015 в 03:53
7

В наши дни я обычно использую такую ​​библиотеку, как 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   

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

avatar
Jelle Keizer
7 октября 2014 в 13:27
4

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

     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;
        }
Spoo
7 октября 2016 в 19:58
0

Забыть вернуть false, если оно не совпадает. Errgo неверно, так как возвращаемое значение функции не должно «предполагаться», но я знаю, к чему вы идете, по крайней мере, по сравнению с другими ответами.

avatar
ThatOneCoder
6 декабря 2013 в 19:45
3

Многие из предыдущих ответов также будут работать. Тем не менее, это возможно настолько коротко, насколько вы можете сделать это и заставить его делать то, что вы хотите. Вы просто заявляете, что хотите, чтобы он «вернул истину». Поэтому я включил решения, которые возвращают логическое значение 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';
}
ThatOneCoder
23 октября 2014 в 21:02
0

Истинный. Однако Питер просил функцию, которая работала бы со строками символов. Тем не менее, я обновил свой ответ, чтобы вас успокоить.

Tino
26 октября 2014 в 11:08
0

После редактирования ваше решение полностью устарело. Он возвращает 'true' и 'false' как строки, которые оба являются true в логическом смысле. Хотя это хороший шаблон для чего-то вроде underhanded.xcott.com;)

ThatOneCoder
27 октября 2014 в 13:04
0

Ну, Питер только что заявил, что хочет, чтобы оно вернулось как «истина». Так что я решил, что верну то, о чем он просил. Я добавил обе версии, на всякий случай, если это не то, что он хотел.

avatar
Srinivasan.S
18 октября 2013 в 13:01
7

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

$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';
avatar
Ja͢ck
2 августа 2013 в 07:40
20

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

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

function endsWith($haystack, $needle)
{
    return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
Tino
20 февраля 2014 в 21:53
2

+1 Работает с PHP5.1 и лучший ответ IMHO. Но endsWidth должен делать return $needle==='' || substr_compare( ... поэтому он работает так, как ожидалось, для -strlen($needle)===0, что без исправления возвращает endsWith('a','') return false

Ja͢ck
21 февраля 2014 в 02:55
0

@Tino Спасибо ... Мне кажется, что это ошибка в substr_compare() на самом деле, поэтому я добавил PR, чтобы исправить это :)

gx_
9 августа 2015 в 19:47
3

Вызов endsWith('', 'foo') вызывает предупреждение: «substr_compare (): начальная позиция не может превышать исходную длину строки». Возможно, это еще одна ошибка в substr_compare(), но чтобы ее избежать, вам нужна предварительная проверка, например ... || (strlen($needle) <= strlen($haystack) && substr_compare( ... ) === 0);

Tino
20 июля 2018 в 11:35
0

@gx_ Нет необходимости замедлять работу с дополнительным кодом. Просто используйте return $needle === '' || @substr_compare( .., чтобы подавить это предупреждение.

avatar
FrancescoMM
28 июля 2013 в 14:00
8

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

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

Это как-то (на 20% -30%) быстрее. Добавление еще одного теста char, например $ haystack {1} === $ Need {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 не выполняет итерацию по всей строке (но даже в этом случае), это совсем не удобно.

Ja͢ck
2 августа 2013 в 07:51
0

Ускорение есть только в том случае, если первые символы разные.

FrancescoMM
18 сентября 2013 в 08:42
3

@Jack: да, конечно, идея в том, что это происходит статистически, поэтому ускорение обычно составляет 20% -30% по всему набору тестов (включая случаи, когда оно не отличается). Вы получаете много, когда они разные, и очень мало теряете, когда они не такие. В среднем вы получаете эти 30% (зависит от набора, но в основном вы набираете скорость на больших тестах)

Fr0zenFyr
24 марта 2018 в 08:29
0

"но это неподходящий инструмент для этой работы" ... Есть ссылки?

FrancescoMM
24 марта 2018 в 08:40
2

Черт возьми. Я перечислил весь процесс ниже, кого я должен цитировать, более того? Вы бы использовали функцию, которая ищет до конца строки, чтобы сказать вам, что первый символ не является «а»? Кого это волнует? Это неподходящий инструмент, потому что это инструмент для поиска, а не для сравнения, нет необходимости цитировать Аристотеля, чтобы констатировать очевидное!

avatar
user507410
4 июня 2013 в 08:51
5

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

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

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

avatar
Bill Effin Murray
30 июня 2012 в 03:49
4

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

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

Вывод:

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

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

А вот и концы на:

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

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

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

вернет верно или неверно.

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

FrancescoMM
23 января 2014 в 15:05
3

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

Bill Effin Murray
23 января 2014 в 17:34
0

Простота заключается в наборе текста, а не в логике.

Alexis Wilke
2 июля 2014 в 00:33
0

Это не столько логика, сколько возможная оптимизация, на которую указывал Франко. Использование strpos() будет медленным, кроме случаев, когда оно действительно совпадает. strncmp() в этом случае было бы намного лучше.

dkellner
3 сентября 2018 в 13:09
0

Когда вы выполняете такие низкоуровневые функции, вы обычно хотите выбрать наиболее оптимизированное по скорости решение, каким бы сложным оно ни было, поскольку оно будет вызываться миллионы раз. Каждая микросекунда, которую вы здесь выиграете или проиграете, будет иметь очень большое значение. Так что лучше подправить его, черт возьми (а затем забыть о сложности, теперь, когда у вас есть функция), вместо того, чтобы искать взгляды и терять ужасающее количество времени позже, когда вы даже не знаете, что пошло не так. Представьте, что вы проверяете строку размером 2 ГБ, которая не совпадает.

avatar
Salman A
6 мая 2012 в 18:22
1075

Вы можете использовать функцию substr_compare для проверки начала и конца:

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

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

Wim ten Brink
21 апреля 2016 в 11:36
82

Этот ответ попал в Daily WTF! : D См. thedailywtf.com/articles/…

Salman A
21 апреля 2016 в 14:00
0

Обратите внимание, что комментарии @DavidWallace и @FrancescoMM относятся к более старой версии этого ответа. В текущем ответе используется strrpos, который (должен) немедленно выйти из строя, если игла не соответствует началу стога сена.

Welbog
21 апреля 2016 в 14:44
2

Я не понимаю. На основе php.net/manual/en/function.strrpos.php: «Если значение отрицательное, поиск вместо этого начнется с такого количества символов от конца строки, поиск в обратном направлении». Похоже, это означает, что мы начинаем с символа 0 (из-за -strlength($haystack)) и ищем оттуда назад ? Разве это не значит, что вы ничего не ищете? Я также не понимаю !== false части этого. Я предполагаю, что это полагается на причуду PHP, где одни значения «правдивы», а другие «ложны», но как это работает в этом случае?

Salman A
21 апреля 2016 в 15:01
3

@Welbog: например, стог сена = xxxyyy игла = yyy и при использовании strrpos поиск начинается с первого x. Теперь у нас нет успешного совпадения (найдено x вместо y), и мы больше не можем вернуться назад (мы в начале строки), поиск не выполняется немедленно . Об использовании !== false - strrpos в приведенном выше примере вернет 0 или false, а не другое значение. Аналогично, strpos в приведенном выше примере может возвращать $temp (ожидаемая позиция) или false. Я выбрал !== false для согласованности, но вы можете использовать === 0 и === $temp в функциях соответственно.

Salman A
8 октября 2016 в 06:22
10

@spoo уже установлено, что strpos === 0 - ужасное решение, если стог сена большой, а иглы нет.

avatar
Vincent Pazeller
19 апреля 2012 в 20:50
6

вкратце:

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

function endsWith($str, $needle){
   $length = strlen($needle);
   return !$length || substr($str, - $length) === $needle;
}
avatar
biziclop
21 февраля 2012 в 11:52
4

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

Тесты (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

avatar
mpen
24 августа 2011 в 00:07
255

Обновлено 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

FrancescoMM
28 июля 2013 в 15:38
3

Если строки не пустые, как в ваших тестах, это на самом деле как-то (на 20-30%) быстрее: function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;} Я добавил ответ ниже.

mpen
19 ноября 2014 в 00:49
0

@FrancescoMM Я включил вашу версию в свои тесты. Это не похоже на правду; по крайней мере, когда первая буква имеет шанс совпадения 1 из 64.

FrancescoMM
19 ноября 2014 в 07:46
0

странно, это может зависеть от реализации PHP, поскольку я тестировал ее на вашем же наборе, в любом случае спасибо за добавление

Jronny
2 декабря 2014 в 14:22
0

почему вы сказали, что substr_startswith самый быстрый, когда substr_compare_startswith имеет только 133?

mpen
2 декабря 2014 в 16:41
3

@Jronny Потому что 110 меньше 133 ... ??

Jronny
18 декабря 2014 в 03:08
2

Черт, я не знаю, что пришло мне в голову в тот раз. Возможно недосыпание.

FrancescoMM
28 июля 2015 в 14:35
0

Это то, что я получил на том же наборе в среде OsX MAMP на 10000 петель, чтобы подтвердить, что это зависит от настройки. generating tests..........done! substr_startswith: 51.8469810486 ms preg_match_startswith: 1991.78195 ms substr_compare_startswith: 53.2069206238 ms strpos_startswith: 63.8959407806 ms strncmp_startswith: 45.2649593353 ms strncmp_startswith2: 42.7808761597 ms итак ... проведи несколько тестов на своей производственной машине!

rivimey
19 апреля 2016 в 11:01
0

Еще одна реплика на Macbook Pro 2015 года (Core i5) с php 5.6.20. Loops = 20000: генерация тестов ... Готово! substr_startswith: 39.290904998779 ms preg_match_startswith: 1911.6959571838 ms substr_compare_startswith: 37.993907928467 ms strpos_startswith: 51.711082458496 ms strncmp_startswith: 42.64497r756958 ms strncmp_startswith: 42.64497r756958

mpen
23 августа 2016 в 18:13
0

Обновлено для PHP 7. strncmp_startswith2 переместился с 4-го места на 1-е. Большинство функций стали значительно быстрее, за исключением preg_match, который теперь работает вдвое медленнее.

AdamJones
19 сентября 2016 в 16:13
0

@mpen есть ли шанс показать нам ваши предпочтительные альтернативы endWith ()?

mpen
19 сентября 2016 в 16:45
0

@AdamJones Я не придумал никаких альтернатив. Вот что я сейчас использую: gist.github.com/mnpenner/1e35f9f20d0982c541c6ea1fd45ff5a8

Visman
18 ноября 2017 в 04:22
0

preg_quote () - очень медленная функция. with - preg_match_startswith: 2,240,1 мс; без - preg_match_startswith: 258.0 мс

Visman
18 ноября 2017 в 04:35
0

Используйте return preg_match('~\Q' . $needle . '\E~A', $haystack) > 0;

mpen
18 ноября 2017 в 21:26
0

@Visman Вам все равно пришлось бы удваивать обратную косую черту в игле, если бы вы использовали \Q...\E нет? Изменить: Или я думаю, просто \E, вам нужно бежать ... на самом деле я не знаю , как избежать буквального \E. Edit2: Я думаю, вы могли бы str_replace('\\E', '\\E\\\\E\\Q', $needle), что даже уродливее, чем preg_quote. Не уверен, будет ли это быстрее или нет.

Visman
19 ноября 2017 в 12:26
0

@mpen, sandbox.onlinephpfunctions.com/code/… - работает, sandbox.onlinephpfunctions.com/code/… - не работает. Наверное, ошибка. regex101.com/r/kFBxWR/1 - эмулятор работает исправно.

mpen
20 ноября 2017 в 17:23
0

@Visman Да ... но я спросил, нужно ли помещать в строку поиска литерал \E, а не только разделитель начала / конца.

Visman
21 ноября 2017 в 02:15
1

@mpen, я вообще не слона заметил :(

Salman A
15 декабря 2017 в 15:06
1

Эти тесты не годятся для проверки производительности. Что вы делаете, так это используете случайную строку в качестве иглы. В 99,99% случаев совпадения не будет. Большинство функций завершится после сопоставления первого байта. А как насчет случаев, когда совпадение найдено? Какая функция требует меньше всего времени для успешного совпадения? А как насчет случаев, когда совпадают 99% игл, но не последние несколько байтов? Какая функция требует меньше всего времени, чтобы не было совпадений?

mpen
15 декабря 2017 в 19:02
1

@SalmanA Вы поднимаете несколько хороших моментов. Хотя не уверен, что хочу переделывать тестовые примеры прямо сейчас.

Thanh Trung
15 апреля 2018 в 18:12
2

$haystack[0] выдаст сообщение об ошибке, если вы не протестируете его с помощью isset. То же и с иглами. Но если вы добавите тесты, это снизит его производительность

avatar
Dan
28 июня 2011 в 22:40
8

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

startWith () является прямым.

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

ndsWith () использует немного необычный и медленный strrev ():

function endsWith($haystack, $needle) {
   return (strpos(strrev($haystack), strrev($needle)) === 0);
}
Fr0zenFyr
24 марта 2018 в 08:22
0

@FrancescoMM: strpos не является "правильным инструментом" ... Почему? Какие тогда «правильные инструменты»? EDIT: Я прочитал ваш ответ ниже. Я думал, что программирование похоже на изобретение с использованием имеющихся у вас ресурсов ... Итак, нет правильного или неправильного ... только работа или не работа ... производительность вторична.

FrancescoMM
24 марта 2018 в 08:42
0

"потому что это инструмент для поиска, а не для сравнения?" Cit. Аристотель

avatar
Patrick Smith
19 апреля 2011 в 05:05
2

Вот эффективное решение для 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;
}
avatar
Freeman
22 декабря 2010 в 14:40
1

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

function endsWith($haystack, $needle, $case=true) {
  return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
Timo Tijhof
16 ноября 2012 в 15:10
3

$needle следует экранировать preg_quote($needle, '/').

avatar
lepe
15 декабря 2009 в 08:53
27

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

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

function startsWithChar($needle, $haystack)
{
   return ($needle === $haystack[0]);
}

function endsWithChar($needle, $haystack)
{
   return ($needle === $haystack[strlen($haystack) - 1]);
}

$str='|apples}';
echo startsWithChar('|',$str); //Returns true
echo endsWithChar('}',$str); //Returns true
echo startsWithChar('=',$str); //Returns false
echo endsWithChar('#',$str); //Returns false
user1646111
1 августа 2013 в 10:29
1

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

a1an
15 мая 2018 в 14:51
0

Вероятно, он должен проверить, есть ли в строке хотя бы один символ и два параметра поменяны местами

Tino
20 июля 2018 в 11:28
2

Творческий. Иголки со стогами сена. Кстати, есть некрасивое уменьшение с: endsWithChar('','x'), но результат правильный

Heider Sati
17 августа 2020 в 09:24
1

Мне нравится ваш ответ, но он довольно забавный, ... иголка и стог сена - наоборот :) ... то есть вы искали бы иголку в стоге сена, следовательно, это должно быть: return ($ Need == = $ стог сена [0]); , но хороший ответ, спасибо!

lepe
17 августа 2020 в 10:11
1

@HeiderSati: Отличное наблюдение! Это то, о чем говорил @Tino Creative. Needles which contain haystacks. ... Я не уделял достаточно внимания. Спасибо! Я починил это. :)

avatar
bobo
30 октября 2009 в 00:17
3

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

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 на функцию Джеймса Блэка StartWith, потому что strncasecmp на самом деле является нечувствительной к регистру версией strncmp.

Alexis Wilke
25 июня 2014 в 02:45
2

Обратите внимание, что strrev() - это creative , но очень дорого, особенно если у вас есть строки, скажем ... 100 КБ.

nawfal
29 января 2016 в 11:38
0

Чтобы быть уверенным, используйте === вместо ==. 0 - это много чего в PHP.

avatar
James Black
17 сентября 2009 в 02:50
16

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

function startsWith($haystack, $needle, $case=true) {
    if ($case)
        return strncasecmp($haystack, $needle, strlen($needle)) == 0;
    else
        return strncmp($haystack, $needle, strlen($needle)) == 0;
}    
mpen
26 августа 2011 в 15:20
0

как бы вы с этим справились?

James Black
26 августа 2011 в 16:45
0

@Mark - вы можете посмотреть принятый ответ, но я предпочитаю использовать strncmp главным образом потому, что считаю его более безопасным.

mpen
26 августа 2011 в 18:50
0

Я имею в виду конкретно strncmp. Вы не можете указать смещение. Это означало бы, что ваша функцияndsWith должна будет использовать совершенно другой метод.

James Black
27 августа 2011 в 00:15
0

@Mark - Для концов, я бы просто использовал strrpos (php.net/manual/en/function.strrpos.php), но, как правило, в любое время, когда вы собираетесь использовать strcmp, strncmp, вероятно, более безопасный вариант.

avatar
tridian
19 июня 2009 в 16:11
35

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

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

 function endsWith($needle, $haystack) {
     return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
 }
Andrew
2 декабря 2014 в 01:59
2

в php для строковых операций порядок параметров следующий: $ haystack, $ Need. эти функции работают в обратном порядке и действуют как функции массива, где порядок на самом деле равен $ Need, $ haystack.

avatar
Sander Rijken
13 мая 2009 в 21:23
143

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

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;
}
Enrico Detoma
5 августа 2010 в 17:16
2

endsWith() функция имеет ошибку. Его первая строка должна быть (без -1): $expectedPosition = strlen($haystack) - strlen($needle);

AppleGrew
4 января 2011 в 15:46
6

В strlen () нет необходимости. Если строка не начинается с данной иглы, код ur будет без необходимости сканировать весь стог сена.

mpen
3 марта 2011 в 21:26
0

вы думаете, что сканирование всей строки дешевле, чем проверка только начала? я не думаю, что strpos дешевле.

chacham15
26 сентября 2011 в 15:39
5

@Mark да, проверка только начала выполняется НАМНОГО быстрее, особенно если вы делаете что-то вроде проверки типов MIME (или любого другого места, где строка должна быть большой)

wdev
6 августа 2012 в 00:39
2

@mark Я провел несколько тестов со стогом сена на 1000 символов и иглой на 10 или 800 символов, и strpos был на 30% быстрее. Сделайте свои тесты, прежде чем заявлять, что что-то работает быстрее или нет ...

mpen
6 августа 2012 в 00:44
1

@wdev: в вашей строке всегда была игла? strpos будет самым медленным, когда строка даже не содержит иглы (необходимо сканировать все это целиком). а с чем именно сравниваете? используя substr или другие методы? substr должен выделить новую строку, что тоже требует значительных затрат.

wdev
6 августа 2012 в 01:05
0

@Mark Match, совпадение отсутствует и сравнение одинаковых строк: gist.github.com/3268655

mpen
6 августа 2012 в 01:55
0

@wdev: Несправедливое сравнение. В двух из ваших трех тестов игла начинается в начале, и именно здесь strpos превосходит. Запустите его только для «нет совпадения» и strncmp победит. Я не знаю, почему strpos когда-либо выигрывал. Возможно, потому что strncmp выполняет полное сравнение, а не просто равно / не равно. И, кстати, я сделал несколько скамеек, если вы посмотрели дальше в этой ветке; но, тем не менее, я имею право строить предположения.

quietmint
3 декабря 2012 в 03:47
7

Вы должны серьезно подумать о цитировании стрелки типа strpos($haystack, "$needle", 0), если есть любой шанс, что это еще не строка (например, если она исходит от json_decode()). В противном случае [нечетное] поведение по умолчанию strpos() может привести к неожиданным результатам: «Если игла не является строкой, она преобразуется в целое число и применяется как порядковое значение символа.»

Sylvain
2 апреля 2013 в 13:14
0

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

Fabrício Matté
22 ноября 2013 в 18:17
0

return strpos ($ haystack, $ Need, $ expectedPosition) === $ expectedPosition; должен быть лучше, так как он не сканирует всю строку при сбое. Хотя тогда вам понадобится проверка if ($expectedPosition < 0) return false; на случай, если длина иглы больше, чем длина стога сена.

Félix Adriyel Gagnon-Grenier
14 октября 2015 в 18:50
0

это. Мне действительно интересно, почему это не принятая функция startsWith().

nawfal
29 января 2016 в 12:15
0

Это возвращает false для startsWith('abc', ''). Сначала вам нужно проверить пустую строку.

Mike Shiyan
19 декабря 2017 в 11:34
0

Третьи аргументы для всех функций str * pos () не нужны. По умолчанию они равны «0».

avatar
KdgDev
7 мая 2009 в 12:15
48
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);
}

Кредит на :

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

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

Sander Rijken
13 мая 2009 в 21:25
2

strtolower - не лучший способ сделать функции нечувствительными к регистру. В некоторых регионах корпус более сложный, чем просто верхний и нижний.

KdgDev
14 мая 2009 в 11:06
8

Я вижу жалобы и решения нет ... Если ты хочешь сказать, что это плохо, то ты тоже должен привести пример, как это должно быть.

Sander Rijken
6 августа 2010 в 07:34
2

@WebDevHobo: поэтому я сам добавил ответ за день до вашего комментария. Для вашего кода strcasecmp действительно был правильным решением.