Функции startsWith() и endsWith() в PHP
Как я могу написать две функции, которые будет принимать строку и проверять, начинается ли она с указанного символа/строки или заканчивается на него?
Например:
$str = '|apples}';
echo startsWith($str, '|'); // Должно вернуть true
echo endsWith($str, '}'); // Должно вернуть true
5 ответ(ов)
Все ответы до сих пор кажутся чересчур затратными, с множеством ненужных вычислений strlen
, выделений памяти под строки (например, с помощью substr
) и т. д. Функции 'strpos'
и 'stripos'
возвращают индекс первого вхождения $needle
в $haystack
:
function startsWith($haystack, $needle, $case = true)
{
if ($case)
return strpos($haystack, $needle, 0) === 0;
return stripos($haystack, $needle, 0) === 0;
}
function endsWith($haystack, $needle, $case = true)
{
$expectedPosition = strlen($haystack) - strlen($needle);
if ($case)
return strrpos($haystack, $needle, 0) === $expectedPosition;
return strripos($haystack, $needle, 0) === $expectedPosition;
}
Данный подход минимизирует лишние операции и делает код более эффективным. Функции просто проверяют, начинается ли строка с определённого подстроки или заканчивается на неё, без лишних затрат на выделение памяти или вычисление длинны строки там, где это не обязательно.
Этот вопрос уже имеет множество ответов, но в некоторых случаях можно обойтись чем-то более простым, чем все они.
Если строка, которую вы ищете, известна (зашита в коде), вы можете использовать регулярные выражения без каких-либо экранирований и т.п.
Проверка, начинается ли строка с 'ABC':
preg_match('/^ABC/', $myString); // "^" здесь означает начало строки
Проверка, заканчивается ли строка на 'ABC':
preg_match('/ABC$/', $myString); // "$" здесь означает конец строки
В моем простом случае я хотел проверить, заканчивается ли строка на слеш:
preg_match('#/$#', $myPath); // Используйте "#" в качестве ограничителя вместо экранирования слэша
Преимущество: так как это очень коротко и просто, вам не нужно определять функцию (например, endsWith()
), как было показано выше.
Но еще раз — это не решение для всех случаев, а только для очень конкретного.
Ваш код с регулярными выражениями работает правильно, чтобы проверить, начинается ли строка $haystack
с подстроки $needle
и заканчивается ли она на ту же подстроку. Ниже приведены исправленные функции с немного более полными комментариями:
function startsWith($needle, $haystack) {
// Проверяем, начинается ли $haystack с $needle
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function endsWith($needle, $haystack) {
// Проверяем, заканчивается ли $haystack на $needle
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
Функции используют preg_match()
с предобработанным шаблоном, созданным с помощью preg_quote()
, который экранирует специальные символы в строке $needle
. Это гарантирует, что в случае наличия специальных символов в подстроке, они не будут интерпретироваться как метасимволы регулярного выражения.
Таким образом, обе функции корректно проверяют соответствие для начала и конца строк. Если есть другие пожелания по улучшению или оптимизации, дайте знать!
Самое быстрое решение для endsWith():
# Проверяет, заканчивается ли строка на другую строку
function endsWith($haystack, $needle) {
return substr($haystack, -strlen($needle) ) === $needle;
}
Бенчмарк:
# Это решение
function endsWith($haystack, $needle) {
return substr($haystack, -strlen($needle) ) === $needle;
}
# Принятое решение
function endsWith2($haystack, $needle) {
$length = strlen($needle);
return $length === 0 ||
(substr($haystack, -$length) === $needle);
}
# Второй по голосам ответ
function endsWith3($haystack, $needle) {
// ищем начиная с конца, минус длина needle
if ($needle === '') {
return true;
}
$diff = \strlen($haystack) - \strlen($needle);
return $diff >= 0 && strpos($haystack, $needle, $diff) !== false;
}
# Ответ с использованием регулярных выражений
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 # Это решение<br>';
echo $test . 'x endsWith2: ' . $result4 . ' seconds # Принятое решение<br>';
echo $test . 'x endsWith3: ' . $result2 . ' seconds # Второй по голосам ответ<br>';
echo $test . 'x endsWith4: ' . $result3 . ' seconds # Ответ с регулярными выражениями<br>';
exit;
}
timedebug();
Результаты бенчмарка:
10000000x endsWith: 1.5760900974274 seconds # Это решение
10000000x endsWith2: 3.7102129459381 seconds # Принятое решение
10000000x endsWith3: 1.8731069564819 seconds # Второй по голосам ответ
10000000x endsWith4: 2.1521229743958 seconds # Ответ с регулярными выражениями
Если вам нужно наиболее производительное решение для проверки, заканчивается ли строка на другую строку, данное решение endsWith
показывает лучшие результаты по сравнению с остальными вариантами.
Если скорость для вас важна, попробуйте это. (Я считаю, что это самый быстрый метод)
Данный подход работает только для строк и если $haystack состоит лишь из одного символа:
function startsWithChar($needle, $haystack)
{
return ($needle === $haystack[0]);
}
function endsWithChar($needle, $haystack)
{
return ($needle === $haystack[strlen($haystack) - 1]);
}
$str='|apples}';
echo startsWithChar('|',$str); // Возвращает true
echo endsWithChar('}',$str); // Возвращает true
echo startsWithChar('=',$str); // Возвращает false
echo endsWithChar('#',$str); // Возвращает false
Эти функции проверяют, начинается ли строка с заданного символа и заканчивается ли она на заданный символ соответственно.
Как проверить, содержит ли строка конкретное слово?
Удалить пустые элементы массива
Генератор случайных строк на PHP
В чем разница между строками в одинарных и двойных кавычках в PHP?
Как присвоить многострочную строку переменной?