Praca z ciągami znaków
Nette\Utils\Strings to statyczna klasa z przydatnymi funkcjami do pracy z ciągami znaków, głównie w kodowaniu UTF-8.
Instalacja:
composer require nette/utils
Wszystkie przykłady zakładają utworzenie aliasu:
use Nette\Utils\Strings;
Zmiana wielkości liter
Te funkcje wymagają rozszerzenia PHP mbstring
.
lower (string $s): string
Konwertuje ciąg UTF-8 na małe litery.
Strings::lower('Dobrý den'); // 'dobrý den'
upper (string $s): string
Konwertuje ciąg UTF-8 na wielkie litery.
Strings::upper('Dobrý den'); // 'DOBRÝ DEN'
firstUpper (string $s): string
Konwertuje pierwszą literę ciągu UTF-8 na wielką, pozostałych nie zmienia.
Strings::firstUpper('dobrý den'); // 'Dobrý den'
firstLower (string $s): string
Konwertuje pierwszą literę ciągu UTF-8 na małą, pozostałych nie zmienia.
Strings::firstLower('Dobrý den'); // 'dobrý den'
capitalize (string $s): string
Konwertuje pierwszą literę każdego słowa w ciągu UTF-8 na wielką, pozostałe na małe.
Strings::capitalize('Dobrý den'); // 'Dobrý Den'
Modyfikacja ciągu znaków
normalize (string $s): string
Usuwa znaki kontrolne, normalizuje końce linii do \n
, usuwa początkowe i końcowe puste linie, usuwa spacje po
prawej stronie linii, normalizuje UTF-8 do normalnej formy NFC.
unixNewLines (string $s): string
Konwertuje końce linii na \n
używane w systemach uniksowych. Końce linii to: \n
, \r
,
\r\n
, U+2028 line separator, U+2029 paragraph separator.
$unixLikeLines = Strings::unixNewLines($string);
platformNewLines (string $s): string
Konwertuje końce linii na znaki specyficzne dla bieżącej platformy, tj. \r\n
w systemie Windows i
\n
gdzie indziej. Końce linii to: \n
, \r
, \r\n
, U+2028 line separator,
U+2029 paragraph separator.
$platformLines = Strings::platformNewLines($string);
webalize (string $s, ?string $charlist=null, bool $lower=true): string
Modyfikuje ciąg UTF-8 do postaci używanej w adresach URL, tj. usuwa znaki diakrytyczne i wszystkie znaki, oprócz liter alfabetu angielskiego i cyfr, zastępuje myślnikiem.
Strings::webalize('náš produkt'); // 'nas-produkt'
Jeśli inne znaki mają zostać zachowane, można je określić w drugim parametrze funkcji.
Strings::webalize('10. obrázek_id', '._'); // '10.-obrazek_id'
Trzeci parametr pozwala pominąć konwersję na małe litery.
Strings::webalize('Dobrý den', null, false); // 'Dobry-den'
Wymaga rozszerzenia PHP intl
.
trim (string $s, ?string $charlist=null): string
Usuwa spacje (lub inne znaki określone przez drugi parametr) z początku i końca ciągu UTF-8.
Strings::trim(' Hello '); // 'Hello'
truncate (string $s, int $maxLen,
string $append=`'…'
`): string
Skraca ciąg UTF-8 do podanej maksymalnej długości, starając się zachować całe słowa. Jeśli ciąg zostanie skrócony, na końcu dodaje wielokropek (można to zmienić trzecim parametrem).
$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
Wcina tekst wielowierszowy od lewej. Liczbę wcięć określa drugi parametr, a czym wcięcie ma być wykonane – trzeci parametr (domyślnie jest to tabulator).
Strings::indent('Nette'); // "\tNette"
Strings::indent('Nette', 2, '+'); // '++Nette'
padLeft (string $s, int $length, string
$pad=`' '
`): string
Uzupełnia ciąg UTF-8 do podanej długości, powtarzając ciąg $pad
od lewej strony.
Strings::padLeft('Nette', 6); // ' Nette'
Strings::padLeft('Nette', 8, '+*'); // '+*+Nette'
padRight (string $s, int $length,
string $pad=`' '
`): string
Uzupełnia ciąg UTF-8 do podanej długości, powtarzając ciąg $pad
od prawej strony.
Strings::padRight('Nette', 6); // 'Nette '
Strings::padRight('Nette', 8, '+*'); // 'Nette+*+'
substring (string $s, int $start, ?int $length=null): string
Zwraca część ciągu UTF-8 $s
określoną przez pozycję początkową $start
i długość
$length
. Jeśli $start
jest ujemny, zwracany ciąg będzie zaczynał się od znaku -$start
od końca.
Strings::substring('Nette Framework', 0, 5); // 'Nette'
Strings::substring('Nette Framework', 6); // 'Framework'
Strings::substring('Nette Framework', -4); // 'work'
reverse (string $s): string
Odwraca ciąg UTF-8.
Strings::reverse('Nette'); // 'etteN'
length (string $s): int
Zwraca liczbę znaków (nie bajtów) w ciągu UTF-8.
Jest to liczba punktów kodowych Unicode, która może różnić się od liczby grafemów.
Strings::length('Nette'); // 5
Strings::length('červená'); // 7
startsWith (string $haystack, string $needle): bool
Sprawdza, czy ciąg $haystack
zaczyna się od ciągu $needle
.
$haystack = 'Začíná';
$needle = 'Za';
Strings::startsWith($haystack, $needle); // true
Użyj natywnej funkcji str_starts_with()
.
endsWith (string $haystack, string $needle): bool
Sprawdza, czy ciąg $haystack
kończy się ciągiem $needle
.
$haystack = 'Končí';
$needle = 'čí';
Strings::endsWith($haystack, $needle); // true
Użyj natywnej funkcji str_ends_with()
.
contains (string $haystack, string $needle): bool
Sprawdza, czy ciąg $haystack
zawiera ciąg $needle
.
$haystack = 'Posluchárna';
$needle = 'sluch';
Strings::contains($haystack, $needle); // true
Użyj natywnej funkcji str_contains()
.
compare (string $left, string $right, ?int $length=null): bool
Porównuje dwa ciągi UTF-8 lub ich części, ignorując wielkość liter. Jeśli $length
zawiera null,
porównywane są całe ciągi, jeśli jest ujemny, porównywana jest odpowiednia liczba znaków od końca ciągów, w przeciwnym
razie porównywana jest odpowiednia liczba znaków od początku.
Strings::compare('Nette', 'nette'); // true
Strings::compare('Nette', 'next', 2); // true - zgodność pierwszych 2 znaków
Strings::compare('Nette', 'Latte', -2); // true - zgodność ostatnich 2 znaków
findPrefix (…$strings): string
Znajduje wspólny początek ciągów. Lub zwraca pusty ciąg, jeśli wspólny prefiks nie został znaleziony.
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
Zwraca część ciągu $haystack
przed n-tym $nth
wystąpieniem ciągu $needle
. Lub
null
, jeśli $needle
nie został znaleziony. Przy ujemnej wartości $nth
wyszukiwanie
odbywa się od końca ciągu.
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
Zwraca część ciągu $haystack
po n-tym $nth
wystąpieniu ciągu $needle
. Lub
null
, jeśli $needle
nie został znaleziony. Przy ujemnej wartości $nth
wyszukiwanie
odbywa się od końca ciągu.
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
Zwraca pozycję w znakach n-tego $nth
wystąpienia ciągu $needle
w ciągu $haystack
.
Lub null
, jeśli $needle
nie został znaleziony. Przy ujemnej wartości $nth
wyszukiwanie
odbywa się od końca ciągu.
Strings::indexOf('abc abc abc', 'abc', 2); // 4
Strings::indexOf('abc abc abc', 'abc', -1); // 8
Strings::indexOf('abc abc abc', 'd'); // null
Kodowanie
fixEncoding (string $s): string
Usuwa z ciągu nieprawidłowe znaki UTF-8.
$correctStrings = Strings::fixEncoding($string);
checkEncoding (string $s): bool
Sprawdza, czy ciąg jest prawidłowym ciągiem UTF-8.
$isUtf8 = Strings::checkEncoding($string);
Użyj Nette\Utils\Validator::isUnicode().
toAscii (string $s): string
Konwertuje ciąg UTF-8 na ASCII, tj. usuwa znaki diakrytyczne itp.
Strings::toAscii('žluťoučký kůň'); // 'zlutoucky kun'
Wymaga rozszerzenia PHP intl
.
chr (int $code): string
Zwraca określony znak w UTF-8 z punktu kodowego (liczba w zakresie 0×0000..D7FF i 0xE000..10FFFF).
Strings::chr(0xA9); // '©' w kodowaniu UTF-8
ord (string $char): int
Zwraca punkt kodowy określonego znaku w UTF-8 (liczba w zakresie 0×0000..D7FF lub 0xE000..10FFFF).
Strings::ord('©'); // 0xA9
Wyrażenia regularne
Klasa Strings oferuje funkcje do pracy z wyrażeniami regularnymi. W przeciwieństwie do natywnych funkcji PHP, dysponują one
bardziej zrozumiałym API, lepszym wsparciem dla Unicode i przede wszystkim wykrywaniem błędów. Jakikolwiek błąd podczas
kompilacji lub przetwarzania wyrażenia zgłosi wyjątek Nette\RegexpException
.
split (string $subject, string $pattern, bool $captureOffset=false, bool $skipEmpty=false, int $limit=-1, bool $utf8=false): array
Dzieli ciąg na tablicę według wyrażenia regularnego. Wyrażenia w nawiasach również zostaną przechwycone i zwrócone.
Strings::split('hello, world', '~,\s*~');
// ['hello', 'world']
Strings::split('hello, world', '~(,)\s*~');
// ['hello', ',', 'world']``
Jeśli $skipEmpty
jest true
, zwrócone zostaną tylko niepuste elementy:
Strings::split('hello, world, ', '~,\s*~');
// ['hello', 'world', '']
Strings::split('hello, world, ', '~,\s*~', skipEmpty: true);
// ['hello', 'world']
Jeśli podano $limit
, zwrócone zostaną tylko podciągi do limitu, a reszta ciągu zostanie umieszczona w
ostatnim elemencie. Limit –1 lub 0 oznacza brak ograniczeń.
Strings::split('hello, world, third', '~,\s*~', limit: 2);
// ['hello', 'world, third']
Jeśli $utf8
jest true
, przetwarzanie przełącza się w tryb Unicode. Podobnie jak w przypadku
użycia modyfikatora u
.
Jeśli $captureOffset
jest true
, dla każdego dopasowania zwrócona zostanie również jego pozycja w
ciągu (w bajtach; jeśli ustawiono $utf8
, to w znakach). Zmienia to wartość zwracaną na tablicę, w której
każdy element jest parą składającą się z dopasowanego ciągu i jego pozycji.
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
Wyszukuje w ciągu część pasującą do wyrażenia regularnego i zwraca tablicę ze znalezionym wyrażeniem
i poszczególnymi podwyrażeniami lub null
.
Strings::match('hello!', '~\w+(!+)~');
// ['hello!', '!']
Strings::match('hello!', '~X~');
// null
Jeśli $unmatchedAsNull
jest true
, niedopasowane podwzorce są zwracane jako null; w przeciwnym razie
są zwracane jako pusty ciąg lub nie są zwracane:
Strings::match('hello', '~\w+(!+)?~');
// ['hello']
Strings::match('hello', '~\w+(!+)?~', unmatchedAsNull: true);
// ['hello', null]
Jeśli $utf8
jest true
, przetwarzanie przełącza się w tryb Unicode. Podobnie jak w przypadku
użycia modyfikatora u
:
Strings::match('žlutý kůň', '~\w+~');
// ['lut']
Strings::match('žlutý kůň', '~\w+~', utf8: true);
// ['žlutý']
Parametr $offset
można użyć do określenia pozycji, od której należy rozpocząć wyszukiwanie (w bajtach;
jeśli ustawiono $utf8
, to w znakach).
Jeśli $captureOffset
jest true
, dla każdego dopasowania zwrócona zostanie również jego pozycja w
ciągu (w bajtach; jeśli ustawiono $utf8
, to w znakach). Zmienia to wartość zwracaną na tablicę, w której
każdy element jest parą składającą się z dopasowanego ciągu i jego offsetu:
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
Wyszukuje w ciągu wszystkie wystąpienia pasujące do wyrażenia regularnego i zwraca tablicę tablic ze znalezionym wyrażeniem i poszczególnymi podwyrażeniami.
Strings::matchAll('hello, world!!', '~\w+(!+)?~');
/* [
0 => ['hello'],
1 => ['world!!', '!!'],
] */
Jeśli $patternOrder
jest true
, struktura wyników zmieni się tak, że pierwszy element będzie
zawierał tablicę pełnych dopasowań wzorca, drugi element będzie zawierał tablicę ciągów pasujących do pierwszego
podwzorca w nawiasach itd.:
Strings::matchAll('hello, world!!', '~\w+(!+)?~', patternOrder: true);
/* [
0 => ['hello', 'world!!'],
1 => ['', '!!'],
] */
Jeśli $unmatchedAsNull
jest true
, niedopasowane podwzorce są zwracane jako null; w przeciwnym razie
są zwracane jako pusty ciąg lub nie są zwracane:
Strings::matchAll('hello, world!!', '~\w+(!+)?~', unmatchedAsNull: true);
/* [
0 => ['hello', null],
1 => ['world!!', '!!'],
] */
Jeśli $utf8
jest true
, przetwarzanie przełącza się w tryb Unicode. Podobnie jak w przypadku
użycia modyfikatora u
:
Strings::matchAll('žlutý kůň', '~\w+~');
/* [
0 => ['lut'],
1 => ['k'],
] */
Strings::matchAll('žlutý kůň', '~\w+~', utf8: true);
/* [
0 => ['žlutý'],
1 => ['kůň'],
] */
Parametr $offset
można użyć do określenia pozycji, od której należy rozpocząć wyszukiwanie (w bajtach;
jeśli ustawiono $utf8
, to w znakach).
Jeśli $captureOffset
jest true
, dla każdego dopasowania zwrócona zostanie również jego pozycja w
ciągu (w bajtach; jeśli ustawiono $utf8
, to w znakach). Zmienia to wartość zwracaną na tablicę, w której
każdy element jest parą składającą się z dopasowanego ciągu i jego pozycji:
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]],
] */
Jeśli $lazy
jest true
, funkcja zwraca Generator
zamiast tablicy, co przynosi znaczące
korzyści wydajnościowe podczas pracy z dużymi ciągami. Generator pozwala na wyszukiwanie dopasowań stopniowo, zamiast
przeszukiwania całego ciągu naraz. Umożliwia to efektywną pracę nawet z bardzo dużymi tekstami wejściowymi. Ponadto można
w dowolnym momencie przerwać przetwarzanie, jeśli znajdzie się szukane dopasowanie, co oszczędza czas obliczeniowy.
$matches = Strings::matchAll($largeText, '~\w+~', lazy: true);
foreach ($matches as $match) {
echo "Znaleziono: $match[0]\n";
// Przetwarzanie może być w każdej chwili przerwane
}
replace (string $subject, string|array
$pattern, string|callable $replacement=''
, int $limit=-1, bool $captureOffset=false, bool
$unmatchedAsNull=false, bool $utf8=false): string
Zastępuje wszystkie wystąpienia pasujące do wyrażenia regularnego. $replacement
jest albo maską ciągu
zastępczego, albo funkcją zwrotną (callback).
Strings::replace('hello, world!', '~\w+~', '--');
// '--, --!'
Strings::replace('hello, world!', '~\w+~', fn($m) => strrev($m[0]));
// 'olleh, dlrow!'
Funkcja umożliwia również wykonanie wielu zamian, przekazując w drugim parametrze tablicę w formacie
pattern => replacement
:
Strings::replace('hello, world!', [
'~\w+~' => '--',
'~,\s+~' => ' ',
]);
// '-- --!'
Parametr $limit
ogranicza liczbę wykonanych zamian. Limit –1 oznacza brak ograniczeń.
Jeśli $utf8
jest true
, przetwarzanie przełącza się w tryb Unicode. Podobnie jak w przypadku
użycia modyfikatora u
.
Strings::replace('žlutý kůň', '~\w+~', '--');
// 'ž--ý --ůň'
Strings::replace('žlutý kůň', '~\w+~', '--', utf8: true);
// '-- --'
Jeśli $captureOffset
jest true
, dla każdego dopasowania do funkcji zwrotnej przekazana zostanie
również jego pozycja w ciągu (w bajtach; jeśli ustawiono $utf8
, to w znakach). Zmienia to postać przekazywanej
tablicy, w której każdy element jest parą składającą się z dopasowanego ciągu i jego pozycji.
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]]
Jeśli $unmatchedAsNull
jest true
, niedopasowane podwzorce są przekazywane do funkcji zwrotnej jako
null; w przeciwnym razie są przekazywane jako pusty ciąg lub nie są przekazywane:
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']