Rozważać:
$a = 'How are you?';
if ($a contains 'are')
echo 'true';
Załóżmy, że mam powyższy kod. Jaki jest prawidłowy sposób napisania instrukcji if ($a contains 'are')
?
Rozważać:
$a = 'How are you?';
if ($a contains 'are')
echo 'true';
Załóżmy, że mam powyższy kod. Jaki jest prawidłowy sposób napisania instrukcji if ($a contains 'are')
?
Odpowiedzi:
Możesz użyć strpos()
funkcji, która służy do znalezienia wystąpienia jednego ciągu wewnątrz drugiego:
$a = 'How are you?';
if (strpos($a, 'are') !== false) {
echo 'true';
}
Zauważ, że użycie !== false
jest celowe (ani != false
nie === true
zwróci pożądanego wyniku); strpos()
zwraca albo przesunięcie, od którego zaczyna się łańcuch igły w łańcuchu stogu siana, albo wartość logiczną, false
jeśli igły nie znaleziono. Ponieważ 0 jest prawidłowym przesunięciem, a 0 to „falsey”, nie możemy używać takich prostszych konstrukcji jak !strpos($a, 'are')
.
strpos($a, 'are') > -1
testując prawdziwość. Z perspektywy debugowania stwierdzam, że mój mózg marnuje mniej cykli zegara, określając, czy linia jest poprawnie zapisana, gdy nie muszę liczyć ciągłych znaków równości.
Możesz użyć wyrażeń regularnych, lepiej pasujących do słów, niż strpos
wspomniane przez innych użytkowników, zwróci również wartość dla ciągów takich jak taryfa, opieka, gap itp. Można tego po prostu uniknąć w wyrażeniach regularnych, używając granic słów.
Proste dopasowanie dla może wyglądać mniej więcej tak:
$a = 'How are you?';
if (preg_match('/\bare\b/', $a)) {
echo 'true';
}
Po stronie wydajności strpos
jest około trzy razy szybsza i pamiętaj, że kiedy zrobiłem milion porównań na raz, zajęło to preg_match
1,5 sekundy, a strpos
zajęło to 0,5 sekundy.
Edycja: Aby przeszukać dowolną część ciągu, nie tylko słowo po słowie, zaleciłbym użycie wyrażenia regularnego, takiego jak
$a = 'How are you?';
$search = 'are y';
if(preg_match("/{$search}/i", $a)) {
echo 'true';
}
Na i
końcu wyrażenia regularnego zmieniane jest wyrażenie regularne, w którym nie jest rozróżniana wielkość liter, jeśli nie chcesz tego, możesz je pominąć.
Teraz może to być dość problematyczne w niektórych przypadkach, ponieważ ciąg $ $ nie jest w żaden sposób odkażany, to znaczy, w niektórych przypadkach może nie przejść testu, ponieważ $search
użytkownik może dodać ciąg znaków, który może zachowywać się jak jakieś inne wyrażenie regularne ...
Ponadto, oto świetne narzędzie do testowania i przeglądania wyjaśnień różnych wyrażeń regularnych Regex101
Aby połączyć oba zestawy funkcji w jedną funkcję wielofunkcyjną (w tym z wybieraną rozróżnianiem wielkości liter), możesz użyć czegoś takiego:
function FindString($needle,$haystack,$i,$word)
{ // $i should be "" or "i" for case insensitive
if (strtoupper($word)=="W")
{ // if $word is "W" then word search instead of string in string search.
if (preg_match("/\b{$needle}\b/{$i}", $haystack))
{
return true;
}
}
else
{
if(preg_match("/{$needle}/{$i}", $haystack))
{
return true;
}
}
return false;
// Put quotes around true and false above to return them as strings instead of as bools/ints.
}
Oto mała funkcja użyteczna w takich sytuacjach
// returns true if $needle is a substring of $haystack
function contains($needle, $haystack)
{
return strpos($haystack, $needle) !== false;
}
if ($email->contains("@") && $email->endsWith(".com)) { ...
lubif (strpos($email, "@") !== false && substr($email, -strlen(".com")) == ".com") { ...
Podczas gdy większość tych odpowiedzi powie ci, czy w twoim ciągu pojawia się podłańcuch, zazwyczaj nie jest to to, czego szukasz, jeśli szukasz określonego słowa , a nie podłańcuch .
Co za różnica? Podciągi mogą pojawiać się w innych słowach:
Jednym ze sposobów złagodzenia tego byłoby użycie wyrażenia regularnego połączonego z granicami słów ( \b
):
function containsWord($str, $word)
{
return !!preg_match('#\\b' . preg_quote($word, '#') . '\\b#i', $str);
}
Ta metoda nie ma tych samych fałszywych wyników pozytywnych, co wspomniano powyżej, ale ma kilka własnych przypadków skrajnych. Granice słów pasuje na znaki nie-słowa ( \W
), które będzie niczego, co jest nie a-z
, A-Z
, 0-9
, lub _
. Oznacza to, że cyfry i podkreślenia będą liczone jako znaki słowne i takie scenariusze zakończą się niepowodzeniem:
Jeśli chcesz czegoś dokładniejszego niż to, musisz zacząć analizowanie składni w języku angielskim, a to całkiem spora paczka robaków (przy założeniu właściwego użycia składni, co nie zawsze jest dane).
\b
pasuje do dwóch rzeczy, które \W
nie pasują , co sprawia, że świetnie nadaje się do wyszukiwania słów w ciągu: ^
$
Aby ustalić, czy łańcuch zawiera inny ciąg, możesz użyć funkcji PHP strpos () .
int strpos ( string $haystack , mixed $needle [, int $offset = 0 ] )
<?php
$haystack = 'how are you';
$needle = 'are';
if (strpos($haystack,$needle) !== false) {
echo "$haystack contains $needle";
}
?>
UWAGA:
Jeśli igła, której szukasz, znajduje się na początku stogu siana, zwróci pozycję 0, jeśli wykonasz ==
porównanie, które nie zadziała, musisz zrobić===
==
Znak jest porównanie i sprawdza czy zmienna / wyrażenie / stała na lewo ma taką samą wartość jak zmiennej / stałej ekspresji / w prawo.
===
Znak to porównanie, aby zobaczyć, czy dwie zmienne / expresions / stałe są równe AND
mają ten sam typ - czyli oba ciągi lub oba są liczbami całkowitymi.
<?php
$mystring = 'abc';
$findme = 'a';
$pos = strpos($mystring, $findme);
// Note our use of ===. Simply, == would not work as expected
// because the position of 'a' was the 0th (first) character.
if ($pos === false) {
echo "The string '$findme' was not found in the string '$mystring'.";
}
else {
echo "The string '$findme' was found in the string '$mystring',";
echo " and exists at position $pos.";
}
?>
Innym rozwiązaniem byłoby użycie strstr()
lub stristr()
jeśli wyszukiwanie nie uwzględnia wielkości liter.
strstr($a, 'are')
jest znacznie bardziej eleganckie niż brzydkie strpos($a, 'are') !== false
. PHP naprawdę potrzebuje str_contains()
funkcji.
Skorzystaj z dopasowywania bez rozróżniania wielkości liter, używając stripos()
:
if (stripos($string,$stringToSearch) !== false) {
echo 'true';
}
Zobacz komentarze SamGoody i Lego Stormtroopr.
Jeśli szukasz algorytmu PHP do pozycjonowania wyników wyszukiwania na podstawie bliskości / trafności wielu słów, oto szybki i łatwy sposób generowania wyników wyszukiwania tylko przy pomocy PHP:
Problemy z innych metod, takich jak boolean wyszukiwania strpos()
, preg_match()
, strstr()
lubstristr()
Metoda PHP oparta na Vector Space Model i tf-idf (termin częstotliwość – odwrotna częstotliwość dokumentów):
Brzmi to trudne, ale zaskakująco łatwe.
Jeśli chcemy wyszukać wiele słów w ciągu, głównym problemem jest to, jak przypisujemy wagę każdemu z nich?
Gdybyśmy mogli zważyć parametry w ciągu znaków w oparciu o ich reprezentatywność dla ciągu jako całości, moglibyśmy uporządkować nasze wyniki według tych, które najlepiej pasują do zapytania.
Oto idea modelu przestrzeni wektorowej, niedaleko działania wyszukiwania pełnotekstowego SQL:
function get_corpus_index($corpus = array(), $separator=' ') {
$dictionary = array();
$doc_count = array();
foreach($corpus as $doc_id => $doc) {
$terms = explode($separator, $doc);
$doc_count[$doc_id] = count($terms);
// tf–idf, short for term frequency–inverse document frequency,
// according to wikipedia is a numerical statistic that is intended to reflect
// how important a word is to a document in a corpus
foreach($terms as $term) {
if(!isset($dictionary[$term])) {
$dictionary[$term] = array('document_frequency' => 0, 'postings' => array());
}
if(!isset($dictionary[$term]['postings'][$doc_id])) {
$dictionary[$term]['document_frequency']++;
$dictionary[$term]['postings'][$doc_id] = array('term_frequency' => 0);
}
$dictionary[$term]['postings'][$doc_id]['term_frequency']++;
}
//from http://phpir.com/simple-search-the-vector-space-model/
}
return array('doc_count' => $doc_count, 'dictionary' => $dictionary);
}
function get_similar_documents($query='', $corpus=array(), $separator=' '){
$similar_documents=array();
if($query!=''&&!empty($corpus)){
$words=explode($separator,$query);
$corpus=get_corpus_index($corpus, $separator);
$doc_count=count($corpus['doc_count']);
foreach($words as $word) {
if(isset($corpus['dictionary'][$word])){
$entry = $corpus['dictionary'][$word];
foreach($entry['postings'] as $doc_id => $posting) {
//get term frequency–inverse document frequency
$score=$posting['term_frequency'] * log($doc_count + 1 / $entry['document_frequency'] + 1, 2);
if(isset($similar_documents[$doc_id])){
$similar_documents[$doc_id]+=$score;
}
else{
$similar_documents[$doc_id]=$score;
}
}
}
}
// length normalise
foreach($similar_documents as $doc_id => $score) {
$similar_documents[$doc_id] = $score/$corpus['doc_count'][$doc_id];
}
// sort from high to low
arsort($similar_documents);
}
return $similar_documents;
}
PRZYPADEK 1
$query = 'are';
$corpus = array(
1 => 'How are you?',
);
$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
print_r($match_results);
echo '</pre>';
WYNIK
Array
(
[1] => 0.52832083357372
)
PRZYPADEK 2
$query = 'are';
$corpus = array(
1 => 'how are you today?',
2 => 'how do you do',
3 => 'here you are! how are you? Are we done yet?'
);
$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
print_r($match_results);
echo '</pre>';
WYNIKI
Array
(
[1] => 0.54248125036058
[3] => 0.21699250014423
)
PRZYPADEK 3
$query = 'we are done';
$corpus = array(
1 => 'how are you today?',
2 => 'how do you do',
3 => 'here you are! how are you? Are we done yet?'
);
$match_results=get_similar_documents($query,$corpus);
echo '<pre>';
print_r($match_results);
echo '</pre>';
WYNIKI
Array
(
[3] => 0.6813781191217
[1] => 0.54248125036058
)
Istnieje wiele ulepszeń należy dokonać ale model jest sposobem na uzyskanie dobrych wyników z naturalnych zapytań, które nie mają operatorów logicznych takich jak strpos()
, preg_match()
, strstr()
lub stristr()
.
NOTA BENE
Opcjonalnie eliminując nadmiarowość przed wyszukiwaniem słów
zmniejszając w ten sposób rozmiar indeksu i powodując mniejsze zapotrzebowanie na miejsce
mniej We / Wy dysku
szybsze indeksowanie i w konsekwencji szybsze wyszukiwanie.
1. Normalizacja
2. Eliminacja słów kluczowych
3. Podstawienie słownika
Zamień słowa na inne, które mają identyczne lub podobne znaczenie. (np. zamień przypadki „głodnego” i „głodnego” na „głód”)
Można zastosować dalsze miary algorytmiczne (śnieżka) w celu dalszego zredukowania słów do ich podstawowego znaczenia.
Zastąpienie nazw kolorów ich ekwiwalentami szesnastkowymi
Zmniejszenie wartości liczbowych przez zmniejszenie precyzji to inne sposoby normalizacji tekstu.
ZASOBY
Jeśli chcesz uniknąć problemów z „falseyem” i „prawdą”, możesz użyć substr_count:
if (substr_count($a, 'are') > 0) {
echo "at least one 'are' is present!";
}
Jest nieco wolniejszy niż strpos, ale pozwala uniknąć problemów z porównaniem.
false
„jesteś pewien?” ponieważ pozycja na strpos
to0
Inną opcją jest użycie funkcji strstr () . Coś jak:
if (strlen(strstr($haystack,$needle))>0) {
// Needle Found
}
Uwaga: w funkcji strstr () rozróżniana jest wielkość liter. Aby wyszukiwać bez rozróżniania wielkości liter, użyj funkcji stristr () .
Jestem pod wrażeniem, że żadna z odpowiedzi, które tu zastosowano strpos
, strstr
i podobne funkcje nie wspomniały jeszcze o ciągach znaków wielobajtowych (2015-05-08).
Zasadniczo, jeśli masz problemy ze znalezieniem słów ze znakami specyficznymi dla niektórych języków , takich jak niemiecki, francuski, portugalski, hiszpański itp. (Np .: ä , é , ô , ç , º , ñ ), możesz chcieć poprzedzić funkcje z mb_
. Dlatego zaakceptowana odpowiedź użyłaby mb_strpos
lub mb_stripos
(dla dopasowania bez rozróżniania wielkości liter):
if (mb_strpos($a,'are') !== false) {
echo 'true';
}
Jeśli nie możesz zagwarantować, że wszystkie twoje dane są w 100% w UTF-8 , możesz skorzystać z mb_
funkcji.
Dobry artykuł, aby zrozumieć, dlaczego jest absolutne minimum Każdy Programista absolutnie, pozytywnie musi wiedzieć O Unicode i zestawy znaków (bez wymówek!) Przez Joel Spolsky .
W PHP najlepszym sposobem sprawdzenia, czy łańcuch zawiera określony podciąg, jest użycie prostej funkcji pomocniczej, takiej jak ta:
function contains($haystack, $needle, $caseSensitive = false) {
return $caseSensitive ?
(strpos($haystack, $needle) === FALSE ? FALSE : TRUE):
(stripos($haystack, $needle) === FALSE ? FALSE : TRUE);
}
strpos
znajduje pozycję pierwszego wystąpienia ciągu znaków z rozróżnianiem wielkości liter.stripos
znajduje pozycję pierwszego wystąpienia podciągu bez rozróżniania wielkości liter w ciągu.myFunction($haystack, $needle) === FALSE ? FALSE : TRUE
zapewnia, że myFunction
zawsze zwraca wartość logiczną i naprawia nieoczekiwane zachowanie, gdy indeks podciągu wynosi 0.$caseSensitive ? A : B
wybiera albo strpos
albo stripos
do wykonania pracy, w zależności od wartości $caseSensitive
.var_dump(contains('bare','are')); // Outputs: bool(true)
var_dump(contains('stare', 'are')); // Outputs: bool(true)
var_dump(contains('stare', 'Are')); // Outputs: bool(true)
var_dump(contains('stare', 'Are', true)); // Outputs: bool(false)
var_dump(contains('hair', 'are')); // Outputs: bool(false)
var_dump(contains('aren\'t', 'are')); // Outputs: bool(true)
var_dump(contains('Aren\'t', 'are')); // Outputs: bool(true)
var_dump(contains('Aren\'t', 'are', true)); // Outputs: bool(false)
var_dump(contains('aren\'t', 'Are')); // Outputs: bool(true)
var_dump(contains('aren\'t', 'Are', true)); // Outputs: bool(false)
var_dump(contains('broad', 'are')); // Outputs: bool(false)
var_dump(contains('border', 'are')); // Outputs: bool(false)
Poniższa funkcja działa również i nie zależy od żadnej innej funkcji; używa tylko natywnej manipulacji ciągiem PHP. Osobiście nie polecam tego, ale możesz zobaczyć, jak to działa:
<?php
if (!function_exists('is_str_contain')) {
function is_str_contain($string, $keyword)
{
if (empty($string) || empty($keyword)) return false;
$keyword_first_char = $keyword[0];
$keyword_length = strlen($keyword);
$string_length = strlen($string);
// case 1
if ($string_length < $keyword_length) return false;
// case 2
if ($string_length == $keyword_length) {
if ($string == $keyword) return true;
else return false;
}
// case 3
if ($keyword_length == 1) {
for ($i = 0; $i < $string_length; $i++) {
// Check if keyword's first char == string's first char
if ($keyword_first_char == $string[$i]) {
return true;
}
}
}
// case 4
if ($keyword_length > 1) {
for ($i = 0; $i < $string_length; $i++) {
/*
the remaining part of the string is equal or greater than the keyword
*/
if (($string_length + 1 - $i) >= $keyword_length) {
// Check if keyword's first char == string's first char
if ($keyword_first_char == $string[$i]) {
$match = 1;
for ($j = 1; $j < $keyword_length; $j++) {
if (($i + $j < $string_length) && $keyword[$j] == $string[$i + $j]) {
$match++;
}
else {
return false;
}
}
if ($match == $keyword_length) {
return true;
}
// end if first match found
}
// end if remaining part
}
else {
return false;
}
// end for loop
}
// end case4
}
return false;
}
}
Test:
var_dump(is_str_contain("test", "t")); //true
var_dump(is_str_contain("test", "")); //false
var_dump(is_str_contain("test", "test")); //true
var_dump(is_str_contain("test", "testa")); //flase
var_dump(is_str_contain("a----z", "a")); //true
var_dump(is_str_contain("a----z", "z")); //true
var_dump(is_str_contain("mystringss", "strings")); //true
Możesz użyć strstr
funkcji:
$haystack = "I know programming";
$needle = "know";
$flag = strstr($haystack, $needle);
if ($flag){
echo "true";
}
Bez użycia wbudowanej funkcji:
$haystack = "hello world";
$needle = "llo";
$i = $j = 0;
while (isset($needle[$i])) {
while (isset($haystack[$j]) && ($needle[$i] != $haystack[$j])) {
$j++;
$i = 0;
}
if (!isset($haystack[$j])) {
break;
}
$i++;
$j++;
}
if (!isset($needle[$i])) {
echo "YES";
}
else{
echo "NO ";
}
Miałem z tym trochę problemów i ostatecznie zdecydowałem się stworzyć własne rozwiązanie. Bez użycia silnika wyrażeń regularnych :
function contains($text, $word)
{
$found = false;
$spaceArray = explode(' ', $text);
$nonBreakingSpaceArray = explode(chr(160), $text);
if (in_array($word, $spaceArray) ||
in_array($word, $nonBreakingSpaceArray)
) {
$found = true;
}
return $found;
}
Możesz zauważyć, że poprzednie rozwiązania nie są odpowiedzią na to, że słowo jest używane jako przedrostek innego. Aby użyć swojego przykładu:
$a = 'How are you?';
$b = "a skirt that flares from the waist";
$c = "are";
W powyższych przykładach zarówno $a
i $b
zawiera $c
, ale możesz chcieć, aby twoja funkcja powiedziała ci, że $a
zawiera tylko $c
.
$found = false
na początku
Inna możliwość znalezienia wystąpienia słowa z ciągu przy użyciu strstr () i stristr () jest następująca:
<?php
$a = 'How are you?';
if (strstr($a,'are')) // Case sensitive
echo 'true';
if (stristr($a,'are')) // Case insensitive
echo 'true';
?>
i
W stristr
stojaki dla nieczuły.
Wiele odpowiedzi, które używają, substr_count
sprawdza, czy wynik jest >0
. Ale ponieważ if
instrukcja uznaje zero za to samo co fałsz , możesz tego uniknąć i napisać bezpośrednio:
if (substr_count($a, 'are')) {
Aby sprawdzić, jeśli nie występuje, dodaj !
operator:
if (!substr_count($a, 'are')) {
Można to zrobić na trzy różne sposoby:
$a = 'How are you?';
1- stristr ()
if (strlen(stristr($a,"are"))>0) {
echo "true"; // are Found
}
2- strpos ()
if (strpos($a, "are") !== false) {
echo "true"; // are Found
}
3- preg_match ()
if( preg_match("are",$a) === 1) {
echo "true"; // are Found
}
Wersja krótka
$result = false!==strpos($a, 'are');
W celu znalezienia „słowa” zamiast wystąpienia szeregu liter, które mogą być częścią innego słowa, dobrym rozwiązaniem byłoby zastosowanie poniższego.
$string = 'How are you?';
$array = explode(" ", $string);
if (in_array('are', $array) ) {
echo 'Found the word';
}
$string
jestAre are, are?
Powinieneś użyć formatu Insensitive, więc jeśli wprowadzona wartość jest w, small
lub caps
nie będzie to miało znaczenia.
<?php
$grass = "This is pratik joshi";
$needle = "pratik";
if (stripos($grass,$needle) !== false) {
/*If i EXCLUDE : !== false then if string is found at 0th location,
still it will say STRING NOT FOUND as it will return '0' and it
will goto else and will say NOT Found though it is found at 0th location.*/
echo 'Contains word';
}else{
echo "does NOT contain word";
}
?>
Tutaj Stripos znajduje igłę w heystacku bez rozpatrywania skrzynki (małe / czapki).
Może możesz użyć czegoś takiego:
<?php
findWord('Test all OK');
function findWord($text) {
if (strstr($text, 'ok')) {
echo 'Found a word';
}
else
{
echo 'Did not find a word';
}
}
?>
Nie używaj, preg_match()
jeśli chcesz tylko sprawdzić, czy jeden ciąg jest zawarty w innym ciągu. Użyj strpos()
lub strstr()
zamiast, ponieważ będą one szybsze. ( http://in2.php.net/preg_match )
if (strpos($text, 'string_name') !== false){
echo 'get the string';
}
Jeśli chcesz sprawdzić, czy ciąg zawiera kilka szczegółowych słów, możesz:
$badWords = array("dette", "capitale", "rembourser", "ivoire", "mandat");
$string = "a string with the word ivoire";
$matchFound = preg_match_all("/\b(" . implode($badWords,"|") . ")\b/i", $string, $matches);
if ($matchFound) {
echo "a bad word has been found";
}
else {
echo "your string is okay";
}
Jest to przydatne, aby uniknąć spamu na przykład podczas wysyłania wiadomości e-mail.
Funkcja strpos działa dobrze, ale jeśli chcesz case-insensitive
sprawdzić słowo w akapicie, możesz skorzystać z stripos
funkcji PHP
.
Na przykład,
$result = stripos("I love PHP, I love PHP too!", "php");
if ($result === false) {
// Word does not exist
}
else {
// Word exists
}
Znajdź pozycję pierwszego wystąpienia podciągu bez rozróżniania wielkości liter w ciągu.
Jeśli słowo nie istnieje w ciągu, zwróci wartość false, w przeciwnym razie zwróci pozycję słowa.
Musisz użyć identycznych / nie identycznych operatorów, ponieważ strpos może zwrócić 0 jako wartość indeksu. Jeśli lubisz trójskładnikowe operatory, zastanów się nad użyciem następującego (wydaje się trochę wstecz, przyznaję):
echo FALSE === strpos($a,'are') ? 'false': 'true';
Sprawdź, czy ciąg zawiera określone słowa?
Oznacza to, że ciąg musi zostać przetłumaczony na słowa (patrz uwaga poniżej).
Jednym ze sposobów, aby to zrobić i określić separatory, jest użycie preg_split
( doc ):
<?php
function contains_word($str, $word) {
// split string into words
// separators are substrings of at least one non-word character
$arr = preg_split('/\W+/', $str, NULL, PREG_SPLIT_NO_EMPTY);
// now the words can be examined each
foreach ($arr as $value) {
if ($value === $word) {
return true;
}
}
return false;
}
function test($str, $word) {
if (contains_word($str, $word)) {
echo "string '" . $str . "' contains word '" . $word . "'\n";
} else {
echo "string '" . $str . "' does not contain word '" . $word . "'\n" ;
}
}
$a = 'How are you?';
test($a, 'are');
test($a, 'ar');
test($a, 'hare');
?>
Bieg daje
$ php -f test.php
string 'How are you?' contains word 'are'
string 'How are you?' does not contain word 'ar'
string 'How are you?' does not contain word 'hare'
Uwaga: Nie mamy tutaj na myśli słowa dla każdej sekwencji symboli.
Praktyczną definicją słowa jest silnik wyrażeń regularnych PCRE, w którym słowa są podciągami składającymi się wyłącznie ze znaków słownych, oddzielonych znakami niebędącymi słowami.
Znak „słowo” to dowolna litera lub cyfra lub znak podkreślenia, to znaczy dowolny znak, który może być częścią „słowa” Perla. Definicja liter i cyfr jest kontrolowana przez tabele znaków PCRE i może się różnić, jeśli ma miejsce dopasowanie specyficzne dla ustawień regionalnych (..)