Budowanie wyrażeń regularnych PHP

Ostatania modyfikacja: 28 września 2017, kategoria: Php

Wyrażenia regularne pełnią istotną rolę w PHP. Umożliwiają one opisywanie i przetwarzanie długich ciągów znaków. Dzieje się to na zasadzie porównania danego ciągu znaków z określonym wzorem, ułożonym przez programistę.

Czym są wyrażenia regularne?

Wyrażenia regularne to bardzo przydatne narzędzie istniejące nie tylko w języku PHP (na którym dziś się skupimy). Dzięki nim, możliwe jest wykonanie wielu operacji na raz np. wyszukiwanie określonych elementów, walidacja adresów email, walidacja adresów URL oraz zamiana poszczególnych fragmentów strony.

Zadaniem programisty jest zaprojektowanie określonego wzorcu (ang. pattern). Następnie odpowiednie funkcje wyrażeń regularnych próbują dopasować do niego tekst. W artykule opiszę proces projektowania wzorców, które będziesz mógł następnie użyć w odpowiednich funkcjach wyrażeń regularnych.

Operatory wyrażeń regularnych

Operator Opis Stronność
^ Operator początku ciągu znaków. prawostronny
$ Operator końca ciągu znaków. lewostronny
. Operator jednego dowolnego znaku. n/d
[a-z] Dowolne litery od a do z. n/d
[A-Z] Dowolne litery od A do Z. n/d
[0-9] Dowolne cyfry od 0 do 9. n/d
[^ ] Operator negacji zbioru. n/d
* Operator powtórzenia 0 lub więcej razy. lewostronny
+ Operator powtórzenia 1 lub więcej razy. lewostronny
? Operator powtórzenia 1 lub 0 razy. lewostronny
| Operator alternatywy. obustronny
( ) Wyrażenie wewnątrz nawiasów jest atomem (rozpatrujemy je jako całość). n/a
{x} Operator powtórzenia dokładnie ‚x’ razy. lewostronny
{x,y} Operator powtórzenia minimum ‚x’ i maksimum ‚y’ razy. lewostronny

Zaprezentowane operatory na pierwszy rzut oka mogą wydawać się niezrozumiałe. Zanim zaczniemy budować wyrażenia regularne, musisz poznać jeszcze kilka ważnych informacji. To czy operator jest lewostronny, prawostronny czy obustronny decyduje o rozmieszczeniu argumentu. Jeżeli operator jest lewostronny, to dotyczy atomu znajdującego się po jego lewej stronie np.: Kar*ol – w tym wzorze operator gwiazdki dotyczy atomu litery r, (Karol)* w tym wypadku dotyczy wyrażenia atomowego w nawiasie.

Atom – jest to najmniejsze wyrażenie we wzorze. Nie rozpatrywujemy go na mniejsze składowe. Z atomów zbudowany jest wzór wyrażenia regularnego. Atomem może być pojedyncza litera lub cyfra. Dzięki nawiasom okrągłym, możemy całe wyrażenie znajdujące się wewnątrz nich przedstawić jako atom.

Wydaje się to logiczne. Jeżeli dla operatora lewostronnego podamy cały nawias, wtedy argumentami są wszystkie atomy znajdujące się wewnątrz nawiasu (może być to np. cały napis).

W artykule będę posługiwał się przede wszystkim funkcją preg_match(). Funkcje wyrażeń regularnych rozpoczynające się przedrostkiem preg pochodzą z rodziny PCRE (język Perl) i są bardziej optymalne od funkcji z ereg z rodziny POSIX. Tak podaje dokumentacja i wiele innych źródeł dostępnych w internecie.

Działanie funkcji Preg_match

Funkcja Preg_match() jest podstawową funkcją PHP dotyczącą wyrażeń regularnych. Przyjmuje ona 2 argumenty: wzorzec oraz ciąg znaków. Jeżeli ciąg znaków zostanie pomyślnie dopasowany do wzorca – zwraca wartość logiczną true, w przeciwnym razie false.

int preg_match ( string $wzorzec , string $ciag_znakow )

Przekazując wzorzec do funkcji należy pamiętać aby umieścić go pomiędzy dwoma slashami. Przykładowe wywołanie funkcji może wyglądać następująco:

<?php
	if (preg_match('/abc/', 'abcdabcdabcd'))
	{
		echo "Wzorzec 'abc' pasuje do ciągu znaków 'abcdabcdabcd'";
	}

	else
	{
		echo "Błąd: Wzorzec nie pasuje do ciągu znaków";
	}
?>

Praktyczne wykorzystanie operatorów

Przyjrzyjmy się jak działa kod umieszczony w poprzednim akapicie. Prosty wzorzec abc pasuje do ciągu znaków abcdabcdabcd. Co więcej, został on dopasowany w wielu miejscach:

preg-match

Posłużmy się operatorem początku ciągu znaków (czyli ^). Dopiszmy go do naszego wzorca ^abc i porównajmy do tego samego ciągu znaków:

preg-match

Tym razem wzorzec został dopasowany tylko jeden raz. Zamiast operatora  początku ciągu można także użyć operator końca. Można także użyć obydwu operatorów na raz. Po zmianie operatorów wzorzec nie zostanie dopasowany (chyba że zmienimy ciąg znaków). Przyjrzyjmy się obrazkowi:

wyrażenia-regularne-php

Operatory początku i końca dają małe możliwości. Aby lepiej zrozumieć wyrażenia regularne, zróbmy kilka testów z operatorem dowolnego znaku ‚.‚ i operatorami powtórzeń.

Operator kropki . zastępuje jeden dowolny znak. Nie można określić czy jest to operator lewostronny czy prawostronny, ponieważ nie przyjmuje on argumentów. Używając operatorów powtórzeń, należy pamiętać, że dotyczą one atomu znajdującego się po lewej stronie operatora. Spójrz na przykład:

wyrażenia-regularne

Czas na operatory powtórzeń. Użyję *, ? oraz +. Ich opis znajdziesz w tabelce na samej górze artykułu. Są to operatory lewostronne, czyli najważniejszy jest atom znajdujący się po lewej stronie operatora. Pamiętaj że atomem może być także cały nawias:

wyrażenia regularne php budowa

Robi się coraz ciekawiej. Proponują przetestować nawiasy oraz grupy znaków [a-z], [A-Z] i [0-9]. Wszystko odbywa się w ten sam sposób, należy tylko zapamiętać, że nawias jest traktowany jako jeden znak czyli atom. Grupy znaków w nawiasach kwadratowych także traktujemy jako jeden atom.

preg php

Na obrazku wyżej, ostatni przykład musi zaczynać się od przynajmniej jednej dużej litery. Następnie maksymalnie jeden raz może pojawić się litera a. Następnie wiele razy może się powtórzyć końcówka rol. Napis musi kończyć się końcówką rol.

Ostatnimi operatorami są operatory szczegółowego powtarzania (nawiasy klamrowe) oraz operator alternatywy. Alternatywa to funkcja logiczna wybierająca pomiędzy argumentami. Działanie jest bardzo proste:

wyrażenia-regularne-preg-match

Wszystkie operatory zostały przedstawione. Teraz wystarczy trochę poćwiczyć, aby nabrać wprawy. Warto nauczyć się ich na pamięć.Dobrze opanowane wyrażenia regularne dają duże pole do popisu, każdemu kto programuje w PHP.

Walidacja adresu email za pomocą wyrażeń regularnych

Pisanie długich wyrażeń regularnych najlepiej rozbić na kilka osobnych części. Na końcu każdą część zamykamy w nawias tworząc atom i łączymy je innym atomem bądź operatorem.

Najbardziej przydanym i najczęściej stosowanym przypadkiem używania wyrażeń regularnych jest walidacja adresu email. Każdy większy serwis sprawdza poprawność wprowadzonego adresu email. Poprawny adres ma format: [email protected].

Pisząc wyrażenie regularne walidujące adres emailowy, mamy na prawdę dużo możliwości. Możemy ustalić jakiej długości ma być login, czy adres może zawierać cyfry i czy może zaczynać się od cyfry. Możemy ustalić minimalną długość serwera albo dopuszczalne nazwy serwerów (np.: gmail, interia i o2). Możemy także ustalić domenę i dopuszczać w rejestracji tylko końcówki .pl.

Zacznijmy od loginu. Przyjmuję, że login w adresie email powinien mieć długość od 4 do 20 znaków. Dopuszczam w nim wszelkie znaki. Całość łączę w nawias:

Wzorzec walidacji loginu: ([a-z|A-Z|0-9]{4,20})

Między loginem a serwerem znajduje się małpa, ale ten znak dodamy na końcu łącząc poszczególne atomy. Czas na serwer. Przyjmijmy, że powinien mieć on długość od 2 do 10 znaków. Wszystko będzie analogicznie jak w przykładzie wyżej, zmieni się tylko ilość znaków:

Wzorzec walidacji serwera: ([a-z|A-Z|0-9]{2,10})

Między loginem a domeną musi znajdować się kropka, dodamy ją na samym końcu podczas łączenia atomów. Ostatnim krokiem jest domena. Mogli byśmy ograniczyć ją od 2 do 3 znaków, jednak na potrzeby kursu przyjmuję, że chcemy adresy email Polaków, Niemców oraz domeny „.com”. Posłużymy się operatorem alternatywy:

Wzorzec walidacji domeny: (pl|gr|com)

Ostatnim krokiem jest połączenie wszystkich atomów w jeden wzorzec. Nie można zapomnieć o znaku początku i końca ciągu znaków. Uwaga! Ponieważ kropka jest operatorem wyrażeń regularnych, a chcemy użyć znaku kropki jako oddzielenie serwera od domeny, dlatego poprzedzamy ją dwoma backslashami. Ostateczna postać wyrażenia:

Walidacja adresu email: /^([a-z|A-Z|0-9]{4,20})@([a-z|A-Z|0-9]{2,10})\\.(pl|gr|com)$/

<?php

	if (isset($_GET['email']))
	{
		$email = $_GET['email'];
		$wynik = preg_match('/^([a-z|A-Z|0-9]{4,20})@([a-z|A-Z|0-9]{2,10})\\.(pl|gr|com)$/', $email);

		if ($wynik)
		{
			echo "Wpisany adres jest poprawny! :)";
		}
		else echo "Błąd: proszę wpisać poprawny adres email!";

	}

?>

Standardowo nie wklejam żadnych gotowców. Pełno gotowych rozwiązań można znaleźć w internecie.

Użytkownik Darek napisał:

04 listopada 2013


Artykuł przydał się podczas ogarniania tematu :) aż wstyd się przyznać, że pracuję w PHP od ponad 1 roku a wyrażenia regularne były dla mnie obce – bo nie było pilnej potrzeby żeby umieć… zawsze były na to gotowe przykłady.

Użytkownik Mr-Auto napisał:

17 listopada 2013


W ‚walidacje adresu email’ lepiej się nie bawić,
podany kod nie akceptuje kropki przed @, akceptuje tylko kilka określonych ‚końcówek’ itd.

A przecież jest w php funkcja filter_var która bardzo dobrze sprawdza poprawność adresu email

Użytkownik Karol napisał:

17 listopada 2013


Jak uważasz mistrzu. Walidacja email to przypadkowy temat, aby pokazać jak zlepiać długie formuły wyrażeń regularnych w jedną :).

Użytkownik Adam napisał:

11 września 2014


Fajny tekst. To sztuka (i chyba talent) by o rzeczach tak skomplikowanych jak wyrazenia regularne mowic w sposob prosty i zrozumialy. Autor ma taki talent. :)

Użytkownik Adam W. napisał:

02 czerwca 2015


Akurat rozgryzałem temat wyrażeń regularnych.Nigdzie nie znalazłem tak jasno opisanego problemu.Uczę się PHP i bardzo mi pomogłeś.Dzieki!

Użytkownik Maciej napisał:

21 września 2015


Wyrażenie ragularne są bardzo przydatne nie tylko do walidacji bardziej przydaje się to do przeszukiwania bazy danych. Pisałem o tym w pracy licencjackiej gdzie wyrażenia regularne to temat rzeka. Bardzo fajny artykuł na pewno się przyda ponieważ teraz ma magisterce bedę chciał rowinąć moj temat i pod bazę danych podpiąć jakiś interfejs graficzny do jej obsługi. I tutaj mi sie to przyda do przeszukiwania bazy klientów ponieważ świat nie jest idealny i czesto zdarza się ze użystkownicy dodaja 2 razy tych samych klientów.

Użytkownik Gregorek napisał:

07 lipca 2017


Jak do tej pory najlepszy artykuł dotyczący tego tematu, przeczytałem go w ramach odświeżenia wiadomości, klarowny, zrozumiały konkretny, takie powinny być artykuły poświęcone zagadnieniom programistycznym. Gratuluje i pozdrawiam!

Użytkownik Radek napisał:

28 lutego 2018


Cześć! Naprawdę ciekawie i dobrze tematycznie opisany temat wyrażeń regularnych w PHP. Potrzebowałem tego typu tekstu, żeby stworzyć walidację treści przetwarzanych plików na mojej stronie. Jako, że pliki użytkowników powinny mieć ściśle określoną strukturę, to wpadłem na pomysł użycia wyrażeń regularnych i metody preg_match(). Miałem początkowo problem z operatorem końca ciągu znaków $, ale w końcu się udało.
Wyrażenie walidujące poprawną nazwę w moim przypadku wygląda tak:

$valNr = ‚/^[a-zA-Z0-9ęóąśłżźćń\.\-_]+$/’;

natomiast numer tak:

$valXYH = ‚/^[0-9]+[.|,]{1}[0-9]+$/’;

Pozdr!

Użytkownik Wojciech Skibiński napisał:

16 marca 2018


Witam serdecznie
Jako programista ocieram się o wyrażenia regularne i czasami mam z tym problem, szczególnie kiedy użytkownikiem aplikacji internetowej np. bloga jest analfabeta lub dyslektyk.
Po lekturze Pańskiego artykułu brakowało mi jeszcze wisienki do tortu w postaci obsługi języka polskiego, czyli naszych polskich znaków w wyrażeniach regularnych: ą, ę, ś itd.
Na stronce http://www.unikod.pl/ogonki.html mamy zwięzłą i uproszczoną wersję tej zawartości -> http://www.unicode.org/charts/ <- a to na wypadek, gdybyśmy chcieli robić coś w aplikacjach wielojęzycznych.
Prosty przykład.
\u00F3 jest wzorcem dla ó, \u0105 dla ą itd.
Po co to komu?
Czasami czytając opisy aukcji, czy treści ogłoszeń widzimy takie rażące błędy jak: "ktury", "komurkowy", "faktóra" itd.
Testując odkryłem, że [a-z] nie zawiera w sobie polskich liter: ą, ę, ó, ł itd.
Dzięki zastosowaniu Unicode możemy walidować wzorce dla znaków diakrytycznych w wielu językach, w tym polskim:
– czy wprowadzony string zawiera najczęściej popełniane błędy ortograficzne,
– czy wprowadzony wyraz np. imię lub nazwisko zaczyna się (ń, ę, ą) lub kończy na niedozwolony znak (ó),
– czy wprowadzony tekst zawiera wzorce wulgaryzmów zaszyte w postaci zwrotów kótas, wystarczy dopasować k\u00F3t.
Oczywiście zastosowania praktyczne pozostawiam Państwa inwencji i pomysłowości osób wpisujących dane do formularzy.

Pozdrawiam
Wojciech Skibiński

Zachęcam Cię do zostawienia komentarza!

Ilość znaków: 0