Как я могу написать две функции, которые будут принимать строку и возвращать, если она начинается с указанного символа / строки или заканчивается этим?
Например:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
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);
}
Используйте это, если вы не хотите использовать регулярные выражения.
$length
не требуется в последней строке endsWith()
. return substr($haystack, -strlen($needle))===$needle;
if
вовсе, передав в $length
качестве третьего параметра substr
: return (substr($haystack, -$length, $length);
. Это обрабатывает случай $length == 0
, возвращая пустую строку, а не всю $haystack
. 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);
}
Кредит для :
Все ответы до сих пор , кажется, делают кучу ненужной работы, strlen calculations
, string allocations (substr)
и т.д. , 'strpos'
и 'stripos'
функции возвращают индекс первого вхождения $needle
в $haystack
:
function startsWith($haystack,$needle,$case=true)
{
if ($case)
return strpos($haystack, $needle, 0) === 0;
return stripos($haystack, $needle, 0) === 0;
}
function endsWith($haystack,$needle,$case=true)
{
$expectedPosition = strlen($haystack) - strlen($needle);
if ($case)
return strrpos($haystack, $needle, 0) === $expectedPosition;
return strripos($haystack, $needle, 0) === $expectedPosition;
}
endsWith()
Функция имеет ошибку. Его первая строка должна быть (без -1): $expectedPosition = strlen($haystack) - strlen($needle);
strpos($haystack, "$needle", 0)
если есть какой - нибудь шанс , что это не является строкой (например, если это исходит от json_decode()
). В противном случае поведение по умолчанию [нечетное] strpos()
может привести к неожиданным результатам: « Если игла не является строкой, она преобразуется в целое число и применяется в качестве порядкового значения символа. »Регулярное выражение работает выше, но с другими настройками, также предложенными выше:
function startsWith($needle, $haystack) {
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function endsWith($needle, $haystack) {
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
Я понимаю, что это было закончено, но вы можете захотеть взглянуть на strncmp, так как он позволяет вам сравнивать длину строки, поэтому:
function startsWith($haystack, $needle, $case=true) {
if ($case)
return strncasecmp($haystack, $needle, strlen($needle)) == 0;
else
return strncmp($haystack, $needle, strlen($needle)) == 0;
}
Основываясь на ответе Джеймса Блэка, вот его конец с версией:
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 для функции JamesW Black StartSith, потому что strncasecmp на самом деле является нечувствительной к регистру версией strncmp.
strrev()
это креативно, но очень дорого, особенно если у вас есть, скажем, 100Kb. ===
вместо того, ==
чтобы быть уверенным. 0
равно многим вещам в PHP. Если скорость важна для вас, попробуйте это (я считаю, что это самый быстрый метод)
Работает только для строк и если $ haystack только 1 символ
function startsWithChar($needle, $haystack)
{
return ($needle[0] === $haystack);
}
function endsWithChar($needle, $haystack)
{
return ($needle[strlen($needle) - 1] === $haystack);
}
$str='|apples}';
echo startsWithChar($str,'|'); //Returns true
echo endsWithChar($str,'}'); //Returns true
echo startsWithChar($str,'='); //Returns false
echo endsWithChar($str,'#'); //Returns false
endsWithChar('','x')
но результат верныйВы также можете использовать регулярные выражения:
function endsWith($haystack, $needle, $case=true) {
return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
preg_quote($needle, '/')
. Вот эффективное решение для 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;
}
Короткие и понятные однострочники без регулярных выражений.
начинается с () прямо вперед.
function startsWith($haystack, $needle) {
return (strpos($haystack, $needle) === 0);
}
endWith () использует слегка причудливую и медленную strrev ():
function endsWith($haystack, $needle) {
return (strpos(strrev($haystack), strrev($needle)) === 0);
}
Обновлено 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
function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;}
я добавил ответ ниже. 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
короче говоря:
function startsWith($str, $needle){
return substr($str, 0, strlen($needle)) === $needle;
}
function endsWith($str, $needle){
$length = strlen($needle);
return !$length || substr($str, - $length) === $needle;
}
Вы можете использовать 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
это прикосновение быстрее для начала, но оно не может проверить конец.
strrpos
который (должен) потерпеть неудачу немедленно, если стрелка не соответствует началу стога сена. -strlength($haystack)
) и ищем оттуда назад ? Разве это не значит, что вы ничего не ищете? Я также не понимаю !== false
части этого. Я предполагаю, что это опирается на причуду PHP, где некоторые значения являются «правдивыми», а другие «ложными», но как это работает в этом случае? xxxyyy
needle = yyy
и strrpos
поиск начинается с первого x
. Теперь у нас нет успешного совпадения (найдено x вместо y), и мы больше не можем идти назад (мы находимся в начале строки), поиск немедленно завершается неудачей . Об использовании !== false
- strrpos
в приведенном выше примере будет возвращено 0 или false, а не другое значение. Аналогично, strpos
в приведенном выше примере может возвращаться $temp
(ожидаемая позиция) или false. Я !== false
согласился, но вы можете использовать === 0
и === $temp
функции соответственно. Почему не следующее?
//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 . "!";
}
Вывод:
Нашел значение в начале стоимостного стога!
Имейте в виду, strpos
вернет false, если игла не была найдена в стоге сена, и вернет 0, если и только если игла была найдена с индексом 0 (AKA начало).
И вот кончается с:
$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 . "!";
}
В этом сценарии нет необходимости использовать функцию launchWith () как
(strpos($stringToSearch, $doesItStartWithThis) === 0)
вернет true или false точно.
Кажется странным, что это так просто, когда все дикие функции работают безудержно.
strpos()
будет медленным, кроме случаев, когда оно совпадает. strncmp()
было бы намного лучше в этом случае. Это может сработать
function startsWith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) == $needle;
}
Источник: https://stackoverflow.com/a/4419658
Сосредоточив внимание на запуске с, если вы уверены, что строки не пусты, добавление теста на первый символ, перед сравнением, strlen и т. Д. Немного ускоряет процесс:
function startswith5b($haystack, $needle) {
return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
}
Это как-то (20% -30%) быстрее. Добавление другого теста с символами, такого как $ haystack {1} === $ needle {1}, кажется, не сильно ускоряет, а может даже замедлять.
===
кажется быстрее чем ==
условный оператор (a)?b:c
кажется быстрее чемif(a) b; else c;
Для тех, кто спрашивает "почему бы не использовать strpos?" называя другие решения "ненужной работой"
strpos быстр, но не подходит для этой работы.
Чтобы понять, вот небольшая симуляция в качестве примера:
Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c
Что делает компьютер "внутри"?
With strccmp, etc...
is a===b? NO
return false
With strpos
is a===b? NO -- iterating in haysack
is a===c? NO
is a===d? NO
....
is a===g? NO
is a===g? NO
is a===a? YES
is 1===1? YES -- iterating in needle
is 2===3? YES
is 4===4? YES
....
is 8===8? YES
is c===x? NO: oh God,
is a===1? NO -- iterating in haysack again
is a===2? NO
is a===3? NO
is a===4? NO
....
is a===x? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
is a===b? NO
...
... may many times...
...
is a===b? NO
is a===a? YES -- iterating in needle again
is 1===1? YES
is 2===3? YES
is 4===4? YES
is 8===8? YES
is c===c? YES YES YES I have found the same string! yay!
was it at position 0? NOPE
What you mean NO? So the string I found is useless? YEs.
Damn.
return false
Предполагая, что strlen не выполняет итерацию всей строки (но даже в этом случае), это совсем не удобно.
Вот две функции, которые не вводят временную строку, которая может быть полезна, когда иглы существенно большие:
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(
... так что он работает, как и ожидалось, для -strlen($needle)===0
которого, без исправления, делает endsWith('a','')
возвратfalse
substr_compare()
самом деле ошибка , поэтому я добавил PR, чтобы исправить это :)endsWith('', 'foo')
вызывает предупреждение: «substr_compare (): начальная позиция не может превышать начальную длину строки». Может быть, это еще одна ошибка substr_compare()
, но чтобы ее избежать, вам нужна предварительная проверка, например ... || (strlen($needle) <= strlen($haystack) && substr_compare(
...) === 0);
return $needle === '' || @substr_compare(
.., чтобы подавить это предупреждение. Я надеюсь, что приведенный ниже ответ может быть эффективным, а также простым:
$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';
Многие из предыдущих ответов будут работать так же хорошо. Тем не менее, это, возможно, так коротко, как вы можете сделать это и сделать то, что вы хотите. Вы просто заявляете, что хотите, чтобы он «вернул истину». Поэтому я включил решения, которые возвращают логическое значение 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';
}
'true'
и в 'false'
виде строк, которые оба true
имеют логическое значение. Это хороший пример для чего-то вроде underhanded.xcott.com ;)Я бы сделал это так
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;
}
Я обычно заканчиваю тем, что хожу с библиотекой типа 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
Библиотека полна других полезных функций.
strpos($sHaystack, $sNeedle) == 0
как это strpos($sHaystack, $sNeedle) === 0
? Я вижу ошибку, когда false == 0
оценивает true
. $ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot
На этот вопрос уже есть много ответов, но в некоторых случаях вы можете согласиться на что-то более простое, чем все они. Если искомая строка известна (жестко закодирована), вы можете использовать регулярные выражения без кавычек и т. Д.
Проверьте, начинается ли строка с «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()
), как показано выше.
Но опять же - это не решение для каждого случая, только это очень конкретное.
@
, чтобы /
не пришлось экранировать косую черту ( ). Смотрите пример № 3 здесь: php.net/manual/en/function.preg-match.php . Просто рекомендация:
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)));
}
Эта дополнительная строка, сравнивающая первый символ строк, может немедленно вернуть ложный регистр , поэтому многие ваши сравнения будут намного быстрее (в 7 раз быстрее, когда я измерял). В истинном случае вы практически не платите за производительность этой единственной линии, так что я думаю, что это стоит того. (Кроме того, на практике, когда вы тестируете много строк для определенного начального блока, большинство сравнений завершится неудачей, поскольку в типичном случае вы что-то ищете.)
startsWith("123", "0")
даетtrue
Ответ на 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
Конечно, этот эталонный тест все еще не может быть абсолютно беспристрастным, но он также проверяет эффективность алгоритмов, когда также используются частично совпадающие иглы.
Не уверен, почему это так сложно для людей. Substr отлично справляется с работой и эффективен, так как вам не нужно искать всю строку, если она не совпадает.
Кроме того, поскольку я проверяю не целочисленные значения, а сравниваю строки, мне не нужно беспокоиться о строгом === случае. Тем не менее, === это хорошая привычка.
function startsWith($haystack,$needle) {
substring($haystack,0,strlen($needle)) == $needle) { return true; }
return false;
}
function endsWith($haystack,$needle) {
if(substring($haystack,-strlen($needle)) == $needle) { return true; }
return false;
}
или даже лучше оптимизирован.
function startsWith($haystack,$needle) {
return substring($haystack,0,strlen($needle)) == $needle);
}
function endsWith($haystack,$needle) {
return substring($haystack,-strlen($needle)) == $needle);
}
Вот безопасная многобайтовая версия принятого ответа, она отлично работает для строк 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);
}
startsWith
нем должно быть$length = mb_strlen($needle, 'UTF-8');
Быстрое решение заканчивается с ():
# 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
s($str)->startsWith('|')
иs($str)->endsWith('}')
помочь, как найти в этой автономной библиотеке .