Работа со строками
Nette\Utils\Strings статический класс, содержащий полезные функции для работы со строками, в основном в кодировке UTF-8.
Установка:
composer require nette/utils
Во всех примерах предполагается, что псевдоним уже создан:
use Nette\Utils\Strings;
С учетом регистра
Для этих функций требуется расширение PHP mbstring
.
lower(string $s): string
Преобразует строку UTF-8 в строчный регистр.
Strings::lower('Dobrý den'); // 'dobrý den'
upper(string $s): string
Преобразует строку UTF-8 в верхний регистр.
Strings::upper('Dobrý den'); // 'DOBRÝ DEN'
firstUpper(string $s): string
Преобразует первую букву строки UTF-8 в верхний регистр, остальные не изменяет.
Strings::firstUpper('dobrý den'); // 'Dobrý den'
firstLower(string $s): string
Преобразует первую букву строки UTF-8 в строчную, остальные не изменяет.
Strings::firstLower('Dobrý den'); // 'dobrý den'
capitalize(string $s): string
Преобразует первую букву каждого слова в строке UTF-8 в верхний регистр, остальные – в нижний.
Strings::capitalize('Dobrý den'); // 'Dobrý Den'
Редактировать строку
normalize(string $s): string
Удаляет управляющие символы, нормализует переносы строк до \n
,
обрезает ведущие и отстающие пустые строки, обрезает правые переносы
строк, нормализует UTF-8 до нормальной формы NFC.
unixNewLines(string $s): string
Преобразует переносы строк в \n
, используемые в системах Unix.
Разрывы строк: \n
, \r
, \r\n
, U+2028 разделитель строк,
U+2029 разделитель абзацев.
$unixLikeLines = Strings::unixNewLines($string);
platformNewLines(string $s): string
Преобразует переводы строк в символы, характерные для текущей
платформы, т.е. \r\n
в Windows и \n
в другом месте. Разрывы строк:
\n
, \r
, \r\n
, U+2028 разделитель строк, U+2029 разделитель
абзацев.
$platformLines = Strings::platformNewLines($string);
webalize(string $s, ?string $charlist=null, bool $lower=true): string
Изменяет строку UTF-8 до формата, используемого в URL, т.е. удаляет диакритические знаки и заменяет все символы, кроме букв английского алфавита и цифр, на дефис.
Strings::webalize('náš produkt'); // 'nas-produkt'
Если необходимо сохранить другие символы, их можно указать во втором параметре функции.
Strings::webalize('10. obrázek_id', '._'); // '10.-obrazek_id'
Третий параметр можно использовать для подавления преобразования в нижний регистр.
Strings::webalize('Dobrý den', null, false); // 'Dobry-den'
Требуется расширение PHP intl
.
trim(string $s, ?string $charlist=null): string
Обрезает пробелы (или другие символы, указанные вторым параметром) из начала и конца строки UTF-8.
Strings::trim(' Hello '); // 'Hello'
truncate(string $s, int $maxLen,
string $append=`'…'
`): string
Усекает строку UTF-8 до указанной максимальной длины, стараясь сохранить целые слова. Если строка усеченная, то в конец добавляется триплет (можно изменить с помощью третьего параметра).
$text = 'Řekněte, jak se máte?';
Strings::truncate($text, 5); // 'Řekn…'
Strings::truncate($text, 20); // 'Řekněte, jak se…'
Strings::truncate($text, 30); // 'Řekněte, jak se máte?'
Strings::truncate($text, 20, '~'); // 'Řekněte, jak se~'
indent(string $s, int $level=1, string
$indentationChar=`"\t"
`): string
Отступ многострочного текста слева. Количество отступов определяется вторым параметром, который используется для отступов третьего параметра (значение по умолчанию – tab).
Strings::indent('Nette'); // "\tNette"
Strings::indent('Nette', 2, '+'); // '++Nette'
padLeft(string $s, int $length, string
$pad=`' '
`): string
Завершает строку UTF-8 до указанной длины, повторяя строку
$pad
слева.
Strings::padLeft('Nette', 6); // ' Nette'
Strings::padLeft('Nette', 8, '+*'); // '+*+Nette'
padRight(string $s, int $length,
string $pad=`' '
`): string
Завершает строку UTF-8 до указанной длины, повторяя строку $pad
справа.
Strings::padRight('Nette', 6); // 'Nette '
Strings::padRight('Nette', 8, '+*'); // 'Nette+*+'
substring(string $s, int $start, ?int $length=null): string
Возвращает часть строки UTF-8 $s
, заданную начальной позицией
$start
и длиной $length
. Если $start
отрицательный, то
возвращаемая строка будет начинаться с символа -$start
символа
с конца.
Strings::substring('Nette Framework', 0, 5); // 'Nette'
Strings::substring('Nette Framework', 6); // 'Framework'
Strings::substring('Nette Framework', -4); // 'work'
reverse(string $s): string
Изменяет строку UTF-8.
Strings::reverse('Nette'); // 'etteN'
length(string $s): int
Возвращает количество символов (не байтов) в строке UTF-8.
Это количество кодовых точек Unicode, которое может отличаться от количества графем.
Strings::length('Nette'); // 5
Strings::length('červená'); // 7
compare(string $left, string $right, ?int $length=null): bool
Сравнение двух строк UTF-8 или частей строк без учета регистра. Если
$length
содержит null, то сравниваются целые строки, если
отрицательно, то сравнивается соответствующее количество символов с
конца строк, иначе сравнивается соответствующее количество символов с
начала.
Strings::compare('Nette', 'nette'); // true
Strings::compare('Nette', 'next', 2); // true - shoda prvních 2 znaků
Strings::compare('Nette', 'Latte', -2); // true - shoda posledních 2 znaků
findPrefix(…$strings): string
Находит общее начало строк. Или возвращает пустую строку, если общий префикс не найден.
Strings::findPrefix('prefix-a', 'prefix-bb', 'prefix-c'); // 'prefix-'
Strings::findPrefix(['prefix-a', 'prefix-bb', 'prefix-c']); // 'prefix-'
Strings::findPrefix('Nette', 'is', 'great'); // ''
before(string $haystack, string $needle, int $nth=1): ?string
Возвращает часть строки $haystack
перед n-м $nth
вхождением
строки $needle
. Или null
, если $needle
не был найден. Если
$nth
отрицательный, то поиск ведется с конца строки.
Strings::before('Nette_is_great', '_', 1); // 'Nette'
Strings::before('Nette_is_great', '_', -2); // 'Nette'
Strings::before('Nette_is_great', ' '); // null
Strings::before('Nette_is_great', '_', 3); // null
after(string $haystack, string $needle, int $nth=1): ?string
Возвращает часть строки $haystack
после n-го $nth
вхождения
строки $needle
. Или null
, если $needle
не был найден. Если
$nth
отрицательный, то поиск ведется с конца строки.
Strings::after('Nette_is_great', '_', 2); // 'great'
Strings::after('Nette_is_great', '_', -1); // 'great'
Strings::after('Nette_is_great', ' '); // null
Strings::after('Nette_is_great', '_', 3); // null
indexOf(string $haystack, string $needle, int $nth=1): ?int
Возвращает позицию в символах n-го $nth
вхождения строки
$needle
в строку $haystack
. Или null
, если $needle
не был
найден. Если $nth
отрицательный, то поиск ведется с конца
строки.
Strings::indexOf('abc abc abc', 'abc', 2); // 4
Strings::indexOf('abc abc abc', 'abc', -1); // 8
Strings::indexOf('abc abc abc', 'd'); // null
Кодирование
fixEncoding(string $s): string
Удаляет из строки недопустимые символы UTF-8.
$correctStrings = Strings::fixEncoding($string);
toAscii(string $s): string
Преобразует строку UTF-8 в ASCII, т.е. удаляет диакритические знаки и т.д.
Strings::toAscii('žluťoučký kůň'); // 'zlutoucky kun'
Требуется расширение PHP intl
.
chr(int $code): string
Возвращает определенный символ UTF-8 из кодовой точки (число в диапазоне 0×0000…D7FF и 0×E000…10FFFF).
Strings::chr(0xA9); // '©' v kódování UTF-8
ord(string $char): int
Возвращает кодовую точку UTF-8 определенного символа (число в диапазоне 0×0000…D7FF или 0×E000…10FFFF).
Strings::ord('©'); // 0xA9
Регулярные выражения
Класс Strings предоставляет функции для работы с регулярными
выражениями. В отличие от собственных функций PHP, они имеют более
понятный API, лучшую поддержку Unicode и, что самое важное, обнаружение
ошибок. Любая ошибка при компиляции или обработке выражения приведет к
возникновению исключения Nette\RegexpException
.
split(string $subject, string $pattern, bool $captureOffset=false, bool $skipEmpty=false, int $limit=-1, bool $utf8=false): array
Разделяет строку на массив в соответствии с регулярным выражением. Выражения в круглых скобках также будут перехвачены и возвращены.
Strings::split('hello, world', '~,\s*~');
// ['hello', 'world']
Strings::split('hello, world', '~(,)\s*~');
// ['hello', ',', 'world']``
Если $skipEmpty
равен true
, то будут возвращены только
непустые записи:
Strings::split('hello, world, ', '~,\s*~');
// ['hello', 'world', '']
Strings::split('hello, world, ', '~,\s*~', skipEmpty: true);
// ['hello', 'world']
Если $limit
, то будут возвращены только подстроки до предела, а
остальная часть строки будет помещена в последний элемент. Предел –1
или 0 означает отсутствие предела.
Strings::split('hello, world, third', '~,\s*~', limit: 2);
// ['hello', 'world, third']
Если $utf8
равно true
, то оценка переключится в режим Unicode.
Это аналогично указанию модификатора u
.
Если $captureOffset
равен true
, то для каждого встречающегося
совпадения будет возвращена его позиция в строке (в байтах; в символах,
если установлен $utf8
). Это изменяет возвращаемое значение на
массив, каждый элемент которого представляет собой пару, состоящую из
совпадающей строки и ее позиции.
Strings::split('žlutý, kůň', '~,\s*~', captureOffset: true);
// [['žlutý', 0], ['kůň', 9]]
Strings::split('žlutý, kůň', '~,\s*~', captureOffset: true, utf8: true);
// [['žlutý', 0], ['kůň', 7]]
match(string $subject, string $pattern, bool $captureOffset=false, int $offset=0, bool $unmatchedAsNull=false, bool $utf8=false): ?array
Ищет в строке часть, соответствующую регулярному выражению, и
возвращает массив с найденным выражением и каждым подвыражением, или
null
.
Strings::match('hello!', '~\w+(!+)~');
// ['hello!', '!']
Strings::match('hello!', '~X~');
// null
Если $unmatchedAsNull
равен true
, то не захваченные подвыражения
возвращаются как нулевые; в противном случае они возвращаются как
пустая строка или не возвращаются:
Strings::match('hello', '~\w+(!+)?~');
// ['hello']
Strings::match('hello', '~\w+(!+)?~', unmatchedAsNull: true);
// ['hello', null]
Если $utf8
равно true
, то оценка переключается в режим Unicode.
Аналогично указанию модификатора u
:
Strings::match('žlutý kůň', '~\w+~');
// ['lut']
Strings::match('žlutý kůň', '~\w+~', utf8: true);
// ['žlutý']
Параметр $offset
может использоваться для указания позиции, с
которой следует начинать поиск (в байтах; в символах, если установлен
$utf8
).
Если $captureOffset
равен true
, то для каждого встречающегося
совпадения будет также возвращена его позиция в строке (в байтах; если
установлен $utf8
, то в символах). Это превращает возвращаемое
значение в массив, каждый элемент которого представляет собой пару,
состоящую из совпадающей строки и ее смещения:
Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true);
// [['lut', 2]]
Strings::match('žlutý!', '~\w+(!+)?~', captureOffset: true, utf8: true);
// [['žlutý!', 0], ['!', 5]]
matchAll(string $subject, string $pattern, bool $captureOffset=false, int $offset=0, bool $unmatchedAsNull=false, bool $patternOrder=false, bool $utf8=false, bool $lazy=false): array|Generator
Ищет в строке все вхождения, соответствующие регулярному выражению, и возвращает массив массивов, содержащих найденное выражение и каждое подвыражение.
Strings::matchAll('hello, world!!', '~\w+(!+)?~');
/* [
0 => ['hello'],
1 => ['world!!', '!!'],
] */
Если $patternOrder
равен true
, то структура результатов
изменяется таким образом, что первая запись представляет собой массив
полных совпадений шаблона, вторая – массив строк, совпадающих с
первым подшаблоном в круглых скобках, и так далее:
Strings::matchAll('hello, world!!', '~\w+(!+)?~', patternOrder: true);
/* [
0 => ['hello', 'world!!'],
1 => ['', '!!'],
] */
Если $unmatchedAsNull
равен true
, то несовпадающие подшаблоны
возвращаются как нулевые; в противном случае они возвращаются как
пустые строки или не возвращаются:
Strings::matchAll('hello, world!!', '~\w+(!+)?~', unmatchedAsNull: true);
/* [
0 => ['hello', null],
1 => ['world!!', '!!'],
] */
Если $utf8
равно true
, то оценка переключается в режим Unicode.
Аналогично указанию модификатора u
:
Strings::matchAll('žlutý kůň', '~\w+~');
/* [
0 => ['lut'],
1 => ['k'],
] */
Strings::matchAll('žlutý kůň', '~\w+~', utf8: true);
/* [
0 => ['žlutý'],
1 => ['kůň'],
] */
Параметр $offset
может использоваться для указания позиции, с
которой следует начинать поиск (в байтах; в символах, если установлен
$utf8
).
Если $captureOffset
равен true
, то для каждого встречающегося
совпадения будет также возвращена его позиция в строке (в байтах; если
установлен $utf8
, то в символах). Это изменяет возвращаемое
значение на массив, каждый элемент которого представляет собой пару,
состоящую из совпадающей строки и ее позиции:
Strings::matchAll('žlutý kůň', '~\w+~', captureOffset: true);
/* [
0 => [['lut', 2]],
1 => [['k', 8]],
] */
Strings::matchAll('žlutý kůň', '~\w+~', captureOffset: true, utf8: true);
/* [
0 => [['žlutý', 0]],
1 => [['kůň', 6]],
] */
Если $lazy
равно true
, то вместо массива функция возвращает
Generator
, что дает значительный выигрыш в производительности при
работе с большими строками. Генератор позволяет находить совпадения
постепенно, а не обрабатывать всю строку сразу. Это позволяет
эффективно работать с очень большими входными текстами. Кроме того, вы
можете прервать обработку в любой момент, если нашли нужное
совпадение, что экономит вычислительное время.
$matches = Strings::matchAll($largeText, '~\w+~', lazy: true);
foreach ($matches as $match) {
echo "Found: $match[0]\n";
// Processing can be interrupted at any time
}
replace(string $subject, string|array
$pattern, string|callable $replacement=''
, int $limit=-1, bool $captureOffset=false, bool
$unmatchedAsNull=false, bool $utf8=false): string
Заменяет все вхождения, соответствующие регулярному выражению.
$replacement
– это либо маска строки замены, либо обратный вызов.
Strings::replace('hello, world!', '~\w+~', '--');
// '--, --!'
Strings::replace('hello, world!', '~\w+~', fn($m) => strrev($m[0]));
// 'olleh, dlrow!'
Функция также допускает множественную замену, передавая во втором
параметре массив вида pattern => replacement
:
Strings::replace('hello, world!', [
'~\w+~' => '--',
'~,\s+~' => ' ',
]);
// '-- --!'
Параметр $limit
ограничивает количество замен, которые могут
быть сделаны. Предел –1 означает отсутствие предела.
Если $utf8
равно true
, то оценка переключается в режим Unicode.
Это аналогично указанию модификатора u
.
Strings::replace('žlutý kůň', '~\w+~', '--');
// 'ž--ý --ůň'
Strings::replace('žlutý kůň', '~\w+~', '--', utf8: true);
// '-- --'
Если $captureOffset
равен true
, то для каждого встречающегося
совпадения его позиция в строке (в байтах; в символах, если установлен
$utf8
) также будет передана обратному вызову. Это изменяет форму
передаваемого массива, где каждый элемент представляет собой пару,
состоящую из совпадающей строки и ее позиции.
Strings::replace(
'žlutý kůň',
'~\w+~',
function (array $m) { dump($m); return ''; },
captureOffset: true,
);
// dumps [['lut', 2]] a [['k', 8]]
Strings::replace(
'žlutý kůň',
'~\w+~',
function (array $m) { dump($m); return ''; },
captureOffset: true,
utf8: true,
);
// dumps [['žlutý', 0]] a [['kůň', 6]]
Если $unmatchedAsNull
– true
, то несовпадающие подшаблоны
передаются в обратный вызов как null; в противном случае они передаются
как пустая строка или не передаются:
Strings::replace(
'ac',
'~(a)(b)*(c)~',
function (array $m) { dump($m); return ''; },
);
// dumps ['ac', 'a', '', 'c']
Strings::replace(
'ac',
'~(a)(b)*(c)~',
function (array $m) { dump($m); return ''; },
unmatchedAsNull: true,
);
// dumps ['ac', 'a', null, 'c']