Przedstawione w artykule zagadnienia ilustrują sposoby korzystania z funkcji obsługujących wzorce wyrażeń regularnych zgodnych ze standardem Perla. Przeznaczony jest dla osób, które zapoznały się już z ogólną konstrukcją tytułowej biblioteki.
PCRE to, jak wiadomo z poprzednich artykułów, dodana do PHP biblioteka umożliwiająca stosowanie wzorców wyrażeń regularnych zgodnych ze standardem Perla. Pojawienie się jej w PHP przyczyniło się w znacznym stopniu do rozwoju tego języga. PCRE jest o wiele bardziej rozbudowana od standardowej biblioteki w standardzie POSIX, przez co umożliwia wykonywanie skomplikowanych wzorców, które do tej pory były nieosiągalne. W tym artykule wytłumacze działanie funkcji, dzięki którym można pracować z wyrażeniami regularnymi w standardzie Perla. Poniżej przedstawione zostały wszystkie funkcje, z których będę koszystał:
– preg_match(),
– preg_replace(),
– preg_match_all(),
– preg_split(),
– preg_grep(),
– preg_quote().
Podanymi funkcjami będziemy się zajmować po kolei, przedstawiając możliwie najprzydatniejsze przykłady:
I preg_match:
Budowa funkcji preg_match() przedstawia się następująco:
| preg_match(„wzorzec”, „ciąg”, „znalezione”) |
Przedstawiona funkcja składa się z trzech argumentów. Pierwszy „wzorzec” zawiera wzorzec, z którym będzie porównywany łańcuch znaków „ciąg”. Ostatnim argumentem jest tablica, w której zostaną umieszczone pasujące do wzorca elementy. Przykładem zastosowania tej funkcji jest wyciąganie z ciągu znaków adresu e-mail:
| <? $text = „Mój adres e-mail to: [email protected]”; preg_match(„/[ ]?([a-z0-9_-]+@[a-z0-9_-]+.[a-z0-9_-.]+)+?[ ]?/i”, $text, $matches); $count = count($matches); if ($count > 0) { print „Znaleziono pasujące do wzorca dane:<br>”; $i=0; while ($i < $count) { print „- $matches[$i]<br>”; $i++; } } else { print „Nie znaleziono pasujących do wzorca danych!”; } ?> |
Tego rodzaju wzorzec jest bardzo przydatny. Może posłużyć nie tylko celom sprawdzenia poprawności adresu e-mail, ale także przekształceniu jakiegoś tekstu tak, aby wszytstkie pasujące do wzorca adresy były zamieniane w aktywne łącza. Większość poważnych serwisów korzysta właśnie z takich mechanizmów. W podanym niżej przykładzie został przedstawiony podobny skrypt, z tą jednak rożnicą, że werfikuje adresy URL:
| <? $text = „Adres URL mojej strony www to: www.mojastrona.pl”; preg_match(„/[ ]?([a-z0-9_-\:]+?[a-z0-9_-]+.[a-z0-9_-]+[^ ]+?)+?[ ]?/i”, $text, $matches); $count = count($matches); if ($count > 0) { print „Znaleziono pasujące do wzorca dane:<br>”; $i=0; while ($i < $count) { print „- $matches[$i]<br>”; $i++; } } else { print „Nie znaleziono pasujących do wzorca danych!”; } ?> |
Zarówno ten przykład jak i wcześniejszy są bardzo często używane. Wcześniej poruszyłem także temat dotyczący zamiany odszukanych fraz w aktywne łącza. Jak to zrobić? Na pierwszą myśl przychodzi proste rozwiązanie – wystarczy zastosować zwykłą funkcję str_replace(), ale czy to jest najlepsze rozwiązanie? Nie dałoby rady zapisać tego krócej? Ależ tak! Właśnie tego zagadnienia będzie dotyczyła następna opisywana funkcja. Dodam jeszcze, iż funkcję preg_match() stosuje się raczej do sprawdzenia wystąpienia elemetu pasującego do wzorca lub gdy chcemy, tak jak w przykładach, wypisać wszystkie elementy pasujące do wzorca.
II preg_replace:
Składnia tej funkcji jest troszke bardziej rozwinięta od preg_match():
| preg_replace(„wzorzec”, „zmiennik”, „ciąg”, „granica”) |
Analogicznie do poprzedniej funkcji, pierwszym elementem jest „wzorzec”, do którego jest dopasowywany „ciąg” – trzeci element. Wszystkie pasujące fragmenty są zapamiętywane i przekształcone według wzoru podanym w drugim argumencie – „zmiennik”. Ostatnim i opcjonalnym (nie wymaganym) elementem jest „granica”. Podanie tego argumentu ogranicza ilość dokonywanych zmian, np. jeśli podamy wartość „3”, to zostaną zmodyfikowane tylko trzy pierwsze elementy pasujące do wzorca.
Za pomocą objaśnionej przed chwilą funkcji postaram sie teraz zapisać dwa poprzednie skrypty w postaci, w której wszystkie adresy e-mail i URL podane łańcuchu znaków zostały przekształcone w aktywne łącza:
| <? $text = „Mój adres e-mail to: [email protected], a moja strona www to: www.mojastrona.pl Zapraszam do odwiedzenia!”; $wzorzec1 = '/[ ]?([a-z0-9_-]+@[a-z0-9_-]+.[a-z0-9_-.]+)+?[ ]?/i’; $wzorzec2 = '/[ ]?([a-z0-9_-\:]+?[a-z0-9_-]+.[a-z0-9_-]+[^ ]+?)+?[ ]?/i’; $text2 = preg_replace(„$wzorzec1”, „<a href=mailto:\1>\1</a>”, $text); $text2 = preg_replace(„$wzorzec2”, „<a href=\1>\1</a>”, $text2); print „Oryginalna treść:<br>$text<br>Po przekształceniu:<br>$text2<br>n”; ?> |
Powyższy kod może wydawać się troszke skomplikowany. Jeśli jednak nauczysz się prawidłowo pisać wzorce, to tego typu skrypty nie sprawią Ci już żadnego problemu. Warto także zwrócić uwagę, że podany skrypt nie zapewnia całkowicie poprawnej funkcjonaności, gdyż zawiera wiele luk. Możesz go wykorzystywać do swoich celów, ale dla zwiększenia wydajności powinieneś spróbować samodzielnie przeanalizować wszystkie możliwe niezgodności i poprawić je.
Funkcja preg_replace() znajduje swoje zastosowanie także w innym sytuacjach, ale zależą one od Twoich potrzeb i wyobraźni.
III preg_match_all:
Ta funkcja swoją nazwą i budową znacznie przypomina funkcję preg_match():
| preg_match_all(„wzorzec”, „ciąg”, „znalezione”, „kolejność”) |
Omawiana funkcja różni się od preg_match() w niewielkim stopniu. W obu przypadkach podany w „ciąg” łańcuch znaków jest porównywany ze wzorcem „wzorzec”. Następnie wszystkie odnalezione elmenty są przypisywane do tablicy. I tu pojawia się właśnia różnica. Otóż tablica ta jest tablicą dwuwymiarową, której układ zależy od czwartego argumentu – „kolejność”. Może on przyjąć dwie wartości: „PREG_PATTERN_ORDER” lub „PREG_SET_ORDER”. Ponieważ czwarty argument funkcji jest opcjonalny możemy go pominąć. Wtedy zostanie mu przypisana wartośc domyślna – „PREG_PATTERN_ORDER”. W zależności od wybranej wartości zmienia się konstrukcja tabeli, w której będą przechowywane znalezione elementy. Rożnica ta jest ciężka do opisania, więc dla większego zrozumienia przedstawie ją napierw na przykładach.
Na początek zapisze część wspólną dla obu rodzajów:
| <? $text = „<html> <head> <meta name=”author” content=”Imie”> <meta name=”language” content=”pl”> <meta name=”description” content=”Strona przykładowa…”> </head> <body>Strona przykładowa!</body> </html>”; ?> |
Jak zapewne się zorientowałeś, w powyższym kodzie do zmiennej „$text” przypisałem strukture prostej strony internetowej. Teraz wykorzystam te dane do stworzenia skryptu, który pobiera wartości znaczników <meta>. Na początku w czwartym argumencie wykorzystamy parametr „PREG_PATTERN_ORDER”:
| <? preg_match_all(„/<meta[ ]+?name=['”]?(author|language|description)['”]?[ ]+?content=['”]?(['”]+?)['”]?>/i”, $text, $tablica1, „PREG_PATTERN_ORDER”); print „{$tablica1[0][0]} , {$tablica1[0][1]}, {$tablica1[0][2]}<br> {$tablica1[1][0]} , {$tablica1[1][1]}, {$tablica1[1][2]}<br>”; ?> |
Analizując wyniki działania powyższego skryptu można zauważyć, że „$tablica1[0]” zawiera elementy pasujące do całego wzorca, a „$tablica[1]” pierwszy elment zamknięty w nawiasach podwzorca.
Teraz przedstawię drugi wariant, w którym czwartemu argumentowi omawianej funkcji przypiszę wartość „PREG_SET_ORDER”:
| <? preg_match_all(„/<meta[ ]+?name=['”]?(author|language|description)['”]?[ ]+?content=['”]?(['”]+?)['”]?>/i”, $text, $tablica2, „PREG_SET_ORDER”); print „{$tablica2[0][0]} , {$tablica2[0][1]}<br> {$tablica2[1][0]} , {$tablica2[1][1]}<br> {$tablica2[2][0]} , {$tablica2[2][1]}<br>”; ?> |
Natomiast w tym skrypcie widać, że „$tablica2[0]” zawiera elementy pasujące do całego wzorca, a następnie elmenty pasujące do podwzorca, „$tablic2[1]” zawiera drugi zbiór elementów pasujących do całego wzorca i podwzorca. Indeks główny całej tej tablicy ma tyle wartości, ile jest pasujących do wzorca elementów.
Teraz zapraszam do opisu kolejnej funkcji.
IV preg_split:
Budowa tej funkcji wygląda tak:
| preg_split(„wzorzec”, „ciąg”, „granica”, „opcje”) |
Za pomocą tej funkcji możemy podzielić podany łańcuch znaków – „ciąg” według podanego wzorca „wzorzec”. Dodatkowo za pomocą argumentu „granica” można ograniczyć, ile elementów zostanie zwróconych po podziale. Jeśli podstawisz wartość ’-1′, możesz skorzystać z czwartego argumentu. Może on przyjąć trzy wartości: „PREG_SPLIT_NO_EMPTY”, „PREG_SPLIT_DELIM_CAPTURE” lub „PREG_SPLIT_OFFSET_CAPTURE”. Przy pierwszej z wymienionych wartości zwracana jest tablica, która zawiera tylko niepuste elementy powstałe przy podziale. W drugim typie zwracana jest tablica, która powstała w wyniku podziału łańcucha znaków na podstawie wzorca, a wyrażenie objęte nawiasami w tym wzorcu jest właśnie przypisywane do tablicy. Jeśli chodzi o trzeci typ, to zwracana jest tablica dwuwymiarowa w postaci, w której pierszym zapamiętanym elementem jest wartość powstała w wyniku podzielenia ciągu, a drugim elementem wartość wskaźnika wewnętrznego położenia w łańcuch znaków, gdzie znajduje się podany element. Zarówno trzeci i czwarty argument są opcjonalne, więc nie musisz ich podawać.
Poniżej przedstawiam dwa przykłady zastosowania omawianej funkcji:
| <? $text = „to jest jakiś tekst”; $tablica = preg_split(„//”, $text); ?> |
W powyższym kodzie łańcuch znaków zawarty w zmiennej „$text” został podzielony na odrebne znaki, które zostały zapisane w „$tablica”. Jest to dość często używany skrypt, dzięki któremu można wykonywać skomplikowane operacje, np. szyfrowanie danych itp.
W następnym przykładzie zilustruje zasade korzystania z pozostałych dwóch opcjonalnych argumentów:
| <? $text = „to jest jakiś tekst”; $tablica = preg_split(„/ /”, $text, -1, „PREG_SPLIT_OFFSET_CAPTURE”); ?> |
Teraz „$tablica” jest tablicą dwuwymiarową, gdzie „$tablica[0][0]” zawiera pierwszy element po podziale, „$tablica[0][1]” zawiera wartość wskaźnika położenia tego elmentu w łańcuchcu znaków „$text”. Analogiczną budowę mają kolejne elementy tej tablicy, tzn. „$tablica[1][0]” zawiera kolejny element powstały po podziale, a „$tablica[1][1]” wartość wskaźnika jego położenia w łańcuchu znaków i tak dalej.
V preg_grep:
Kolejna omawiana funkcja przedstawia się następująco:
| preg_grep(„wzorzec”, „tablica”) |
W tej funkcji zwracane są wszystkie elementy tablicy „tablica”, które pasują do wzorca „wzorzec”. Jest przydatna, gdyż zmniejsza objętość kodu, jaki musiałbyś zastosować przy porównaniach, np. przy pomocy funkcji preg_match().
Prosty przykład zastosowania znajduje się poniżej:
| <? $tablica = array(„jakis tekst”, „44”, „jeszcze inny tekst”); $szukane = preg_grep(„/^([^0-9]+)$/”, $text, -1, „PREG_SPLIT_OFFSET_CAPTURE”); ?> |
W tablicy „$szukane” powinny zostać umieszczone wszystkie elementy pasujące do wzorca, czyli w tym wypadku elementy nie będące liczbami.
VI preg_quote:
Składnia ostatniej omawianej funkcji przedstawia się następująco:
| preg_quote(„ciąg”, „granica”) |
Efekty działania tej funkcji nie są niczym nadzwyczajnym. Dodaje ona znak odwrotnego ukośnika przed każdym znakiem wyrażenia regularnego. W drugim (opcjonalnym) argumencie mogą zostać użyte znaki ucieczki, które także zostaną poprzedzone znakiem odwrotnego ukośnika.
Prosty przykład zastosowania:
| <? $text = „przykład dodawania: 2+2=4, a teraz przykład dzielenia: 4/2=2”; $text2 = preg_quote($text, „/”); ?> |
Zastosowanie w tym przykładzie omawianej funkcji ma swoje uzasadnienie, np. znak „+” umieszczony w przykładzie działania może zmienić funkcjonalność wyrażenia. To samo dotyczy znacznika „/”. Jest on używany przez funkcje standardu PCRE i dodatkowe pojawienie się tego znacznika może wywołać nieoczekiwane efekty. Proszę zwrócić uwagę, iż znak „/” nie jest uznawany domyślnie za znak należący do wyrażeń regularnych i należało go podać w drugim argumencie.
Temat zastosowania funkcji standardu PCRE jest bardzo obszerny, a zawarte w tym artykule zagadnienia miały tylko zilustrować ich działanie. Nic nie zastąpi wkładu indywidualnego, dlatego też polecam, aby na podstawie zamieszczonych tu przykładów próbować samemu tworzyć podobne skrypty.
