r05_t.pdf

(335 KB) Pobierz
Oto przyk³ady stylów nag³ówków:
Rozdział 5
Szukając wzorców
W niniejszym rozdziale omówimy następujące tematy:
Czym są wyrażenia, w najprostszej formie.
Jak uzyskać lepsze rezultaty, poszerzając zakres działań.
Funkcje PHP dodający mocy wyrażeniom prostym.
Jak tworzyć proste oraz zaawansowane aplikacje wyszukiwawcze.
No dobrze, teraz już każdy z nas powinien być świadomy poczynionych postępów i tego, że nasz statek PHP
wypływa na szerokie wody. W niniejszym rozdziale przyjrzymy się wyrażeniom prostym i sprawdzimy, jakiego
rodzaju manipulacje na łańcuchach one umożliwiają.
Mówiąc najogólniej, wyrażenia proste umożliwiają dopasowywanie wzorców w łańcuchach. Dopasowywanie
możemy zacząć, wybierając określoną literę (powiedzmy "a"). Możemy jednak posunąć się dalej i
przeprowadzać dopasowywanie całych zestawów liter, a nawet znaków nimi nie będących. Zależy to tylko od
tego, na ile pozwala nasze doświadczenie lub koniecznego stopnia skomplikowania programu.
Zanurzmy na chwilę stopy w głębszej wodzie, nie zanurzając się w niej jednak całkowicie. Przyjrzyjmy się
wyrażeniu zaprezentowanemu poniżej, które, można w to wierzyć lub nie, jest wyrażeniem prostym, służącym
do sprawdzania poprawności adresu email (każdy chyba zdaje sobie sprawę z jego potencjalnej przydatności.
^([a-zA-Z0-9._-]+)@([a-zA-Z0-9-])+(\.[a-zA-Z0-9-]+)+$
Czy widać o co chodzi? Nie będziemy jednak uciekać przed takimi wyrażeniami. Zajmiemy się nimi wkrótce, a
po zakończeniu tej części rozdziału będziemy mieli wystarczającą wiedzę, by zrozumieć sposób ich działania.
Naprawdę!
Niezależnie od swego złożonego wyglądu superkodu, wyrażenia proste bez funkcji są bezużyteczne. Chodzi tu o
funkcje wykorzystujące wyrażenia i wykonujące na ich podstawie operacje na łańcuchach. W miarę lektury tej
części rozdziału zapoznamy się z najbardziej użytecznymi funkcjami PHP, operującymi z wykorzystaniem
wyrażeń prostych oraz z ich zastosowaniem w skryptach.
Proste dopasowywanie wzorców
Przede wszystkim jednak, musimy najpierw nauczyć się budowania wyrażeń prostych! Teorii i konstrukcji
wyrażeń prostych poświęcono całe tomy, a zatem nie powinniśmy oczekiwać, że w ciągu jednej nocy, ani dzięki
lekturze tej części rozdziału, staniemy się znawcami tego tematu. Nauka tworzenia wyrażeń prostych nie
zajmuje wiele czasu, a gdy opanujemy podstawy, reszty nauczymy się stopniowo.
Zanim pójdziemy dalej, musimy zapamiętać, że wyrażenia proste w PHP definiuje się jako łańcuchy,
przekazywane funkcjom i wykonujące określone operacje. Jest to znaczna różnica w stosunku do takich
języków jak Perl, w których wyrażenia proste stanowią część konstrukcji językowych.
A zatem, przejdźmy do dyskusji o podstawach. Mówiąc najogólniej, wyrażenie proste jest wzorcem, który
opisuje poszukiwany przez nas łańcuch. Jest to działanie podobne do funkcji wyszukiwania wyrazów w
dokumentach tekstowych. Wzorzec może być dowolnie prosty lub złożony. Możemy go tworzyć zarówno w
formie łańcucha znakowego, jak i serii klas znakowych. Wyszukiwane mogą być najróżniejsze i
najdziwaczniejsze wzorce — o tym jednak pomówimy później.
W miarę poznawania kolejnych cech wyrażeń prostych PHP, będziemy omawiać je na przykładach, prezentując
łańcuchy, dla których owe wyrażenia zwracają
Zaczynając i kończąc na...
1
55352581.001.png
Spójrzmy na taki oto prosty przykład.
"^one"
Zwróćmy uwagę, że cudzysłowy oznaczają w tym przypadku, że mamy do czynienia z łańcuchem, a nie częścią
wzorca.
Choć jest to bardzo prosty przykład, zastosowano w nim jeden znak specjalny. Znak ^ , określany również jako
karat, sygnalizuje, że wzorzec powinien być dopasowywany tylko do łańcuchów rozpoczynających się od one.
To z kolei oznacza, że gdy zastosujemy to wyrażenie proste na łańcuchu, zwróci ono " one green bottle", ale nie
zwróci "I want one of those green bottles".
Tego rodzaju znaki specjalne określa się jako kotwice, a przeciwieństwem kotwicy ^ jest kotwica $ .
"night$"
Takie wyrażenie oznacza, że wzorzec powinien zwracać tylko te łańcuchy, które kończą się wyrazem night. Po
nałożeniu na łańcuch, wzorzec zwróci więc "in the middle of the night ", ale nie "night and day" ani "had a
nightmare".
Aby wyszukiwanie było bardzo restrykcyjne, możemy zastosować obie, wspomniane kotwice.
"^elephant$"
Powyższe wyrażenie proste zwróci jedynie łańcuch " elephant ", ignorując pozostałe. Oznacza to, że żaden z
następujących łańcuchów: "elephants are cool", "I love elephants" ani "international elephant appreciation
society" nie zostanie uznany za pasujący do wzorca.
Możliwe jest również dopasowywanie całkowicie nierestrykcyjne, w którym pozycja dopasowywanego
łańcucha nie ma żadnego znaczenia.
"elephant"
Takie wyrażenie dopasuje łąńcuchy "I have a little baby elephant ", " elephant s have long memories", a nawet
meet Nigel, my elephant ine friend".
Po tym bardzo osobistym zapoznaniu ze znakami specjalnymi, czas szybko podążyć dalej. Oprócz
wymienionych, istnieją bowiem inne znaki specjalne, które możemy wykorzystywać w wyrażeniach, przydając
im elastyczności i mocy.
Znaki zastępcze
Dzięki zastosowaniu znaków zastępczych w wyrażeniu prostym, możemy określić liczbę wystąpień danego
znaku w poszukiwanym łańcuchu. Dzięki temu, wyszukiwanie staje się znacznie elastyczniejsze.
Modyfikatorami zastępczymi są znaki *, + oraz ?, a odnoszą się one do poprzedzających je znaków lub ich grup.
Każdy z modyfikatorów ma inne znaczenie:
* Dopasowuje łańcuch przy braku lub kilku wystąpieniach.
+ Dopasowuje łańcuch przy jednym wystąpieniu lub więcej.
? Dopasowuje łańcuch przy braku lub jednym wystąpieniu.
Modyfikatory zastępcze odnoszą się do znaków poprzedzających. Spójrzmy na poniższy przykład:
"co+"
Wyrażenie proste w takiej formie wyszuka każdy łańcuch, w którym po literze 'c' występuje jedna lub więcej
liter 'o'. W związku z tym, zwrócone zostaną łańcuchy takie jak "This is cool" i "I'll fetch my coat", ale
pominięty zostanie łańcuch "What a lovely card".
Jeśli zamienimy modyfikator + na *, wówczas wyrażenie zwróci nam wszystkie trzy łańcuchy, gdyż w takim
przypadku kryterium wyszukiwania będzie jedynie litera 'c'. Dzieje się tak dlatego, że znak * dopasowuje
łańcuchy, w których poprzedzająca go litera występuje kilkakrotnie lub nie występuje w ogóle. A zatem,
wyrażenie w takiej formie zwróciłoby również łańcuch nie zawierający ani jednej litery 'o'.
Jako przykład ostatniego z modyfikatorów zastępczych, możemy przytoczyć takie oto wyrażenie:
2
"snakes?"
Za pomocą takiego wyrażenia odszukamy łańcuchy takie jak "There's a snake in my boot" czy " snakes are
cool".
Wydawać się może, że w dwóch powyższych przykładach moglibyśmy obejść się bez modyfikatorów
zastępczych i tak jest rzeczywiście. Gdybyśmy, biorąc jako przykład ostatnie z wyrażeń, użyli
"snake"
jako wyrażenia prostego, wówczas również spowodowałoby ono zwrócenie łańcuchów "There's snake in my
boot" oraz " snake s are cool". Jednakże, jak widać, ostatnia litera 's' w wyrazie "snakes" nie pasuje do wzorca, co
może być niepożądane. Gdybyśmy chcieli, na przykład, wzorzec zawarty w powyższym wyrażeniu prostym
uzupełnić spacją, wówczas nadalibyśmy mu formę
"snake "
Ponieważ określiliśmy tu, że po wyrazie snake ma następować spacja, w związku z tym łańcuch "snakes are
cool" nie zostanie zwrócony, gdyż nie pasuje do wzorca. Jednakże, problem ten moglibyśmy rozwiązać za
pomocą modyfikatorów zastępczych.
"snakes? "
Wyrażenie powyższe można by przetłumaczyć w następujący sposób:
Dopasuj każdy łańcuch, który zawiera wyraz "snake", ewentualnie z literą
"s" na końcu, ale w każdym przypadku kończący się spacją...
Oczywiście, nie trzeba chyba wspominać o tym, że aby dopasować jakikolwiek znak specjalny, należy
poprzedzić go ukośnikiem.
Należy jednak wiedzieć, że zastosowanie modyfikatorów * i + może skończyć się zwróceniem całkowicie
bzdurnych łańcuchów. Na przykład, poszukując czegoś pasującego do wyrazów "about" i "abbey", moglibyśmy
przypuścić, że odpowiednim wyrażeniem będzie w tym przypadku
"ab*"
Jednakże, oprócz właściwych łańcuchów, odnalezione zostałyby również łańcuchy bezsensowne, na przykład:
" abbbbbbbbbbbbb out"
Jest to oczywiście działanie niepożądane i musimy znaleźć bardziej restrykcyjną metodę obsługi takich sytuacji.
Ograniczenie
Na szczęście, możemy posłużyć się cechą wyrażeń prostych, znaną jako ograniczenie . Pozwala ona na
określenie minimalnej i maksymalnej liczby wystąpień danego znaku.
Proste ograniczenie może mieć formę następującą:
"ab{2}"
W ten sposób nakazujemy odszukanie każdego łańcucha, w którym litera "a" poprzedza dokładnie dwie litery
"b". Powyższy przykład pokazuje jak określić dokładną liczbę wystąpień danego znaku, ale omawianej cechy
można użyć również do określenia zakresu liczebności tych wystąpień, wskazując ich liczbę minimalną oraz
maksymalną.
Spójrzmy na taki oto przykład:
"ab{1,2}"
Powyższe wyrażenie proste wyszuka łańcuch, w którym litera "a" poprzedza co najmniej jedną, a najwyżej dwie
litery "b". Gdybyśmy taką formułę zastosowali w poprzednim przykładzie, odszukane zostałyby łańcuchy
"about" oraz "abbey", ale nie "abbbbout".
3
Jeśli pominęlibyśmy liczbę maksymalną, pozostawiając jednak przecinek, określilibyśmy w ten sposób jedynie
minimalną liczbę wystąpień danego znaku. Chcąc odszukać łańcuch, w którym dany znak pojawia się co
najmniej trzykrotnie, wyrażenie miałoby następującą postać:
"ab{3,}"
Byłoby błędem próbować tego samego z pierwszą wartością graniczną, gdyż niemożliwym jest, aby dany znak
pojawiał się mniej niż zero razy. Żądany efekt moglibyśmy uzyskać, wyznaczając zero jako wartość minimalną.
"ab{,3}" // Niedobrze
"ab{0,3}" // Znacznie lepiej
Dopasowywanie dowolnego znaku
Jak dotąd, wykorzystywaliśmy wyrażenia proste do wyszukiwania określonych znaków lub ich sekwencji. Choć
jest to użyteczne, często zdarza się potrzeba użycia rzeczywistego znaku zastępczego, który będzie pasował do
każdego innego znaku.
W tego typu operacjach, możemy używać w skryptach znaku kropki (.). Służy on do reprezentacji dowolnego
znaku, poza znakiem nowego wiersza, w łańcuchu. A zatem:
"co.l"
...wyszuka zarówno " coal ition" jak i " cool ", przy czym, w pierwszym przypadku kropka zastępuje literę "a", zaś
w drugim literę "o".
Wykorzystując znak kropki w połączeniu z ograniczeniami oraz modyfikatorami zastępczymi, możemy tworzyć
bardzo elastyczne wyrażenia. Na przykład, poniższe wyrażenie wyszuka wszystkie wyraz, które zaczynają się
literą "b", kończą literą "e", a pomiędzy tymi literami musi znajdować się co najmniej jeden znak.
"b.+e"
A zatem, wyszukane zostałyby łańcuchy takie jak "I've got a new bike ", " blondie is great", a także "I love brie ".
Proste słowo "be" zostałoby jednak pominięte (ponieważ znak + wskazuje, że pomiędzy literami "b" i "e" musi
znajdować się co najmniej jeden inny znak).
Kwantyfikacja sekwencji znakowych
Wszystkie przytoczone wyżej przykłady dotyczyły dopasowywania wielokrotnych wystąpień indywidualnych
znaków, co należy jednak uczynić, chcąc osiągnąć to samo w stosunku do sekwencji znakowych?
Rozwiązanie polega na ujęciu znaków w nawiasy. A zatem, chcąc odszukać dowolny łańcuch, w którym litera
"b" poprzedza jedną lub więcej sekwencji "an", musimy zastosować wyrażenie proste o postaci:
"b(an)+"
W ten sposób odnalezione zostaną takie łańcuchy, jak " ban " czy " banan a".
Tę samą zasadę można stosować do wszystkich poznanych dotychczas elementów wyrażeń prostych.
Użycie OR
Dalsze uelastycznienie wyrażeń zapewnia nam symbol ' | '. W wyrażeniach prostych można go użyć jako
symbolu OR (lub).
Jak pamiętamy z Rozdziału 2., omawialiśmy tam operator OR , który reprezentowany był symbolem || -
zwróćmy uwagę, że wewnątrz wyrażeń wstawiamy tylko jedną kreskę, gdyż dwie kreski występują w
łańcuchach.
Wróćmy więc do naszego pierwszego przykładu:
"^one"
4
Wyrażenie to, jak pamiętamy, dopasowuje wszystkie łańcuchy rozpoczynające się wyrazem "one", na przykład
"one green bottle". Wykorzystajmy zatem operator OR w wyrażeniu:
"^one|^two"
...które, jak łatwo się domyślić, zwróci wszystkie łańcuchy zaczynające się słowem "one" lub "two".
Zabieg ten możemy stosować we wszystkich omówionych wcześniej technikach. A zatem, poniższe wyrażenie
odszuka wszystkie łańcuchy zawierające słowa "cool" lub "coalition".
"co(ol|alition)"
Klasy znakowe i zakresy
Inną, ciekawą funkcją wyrażeń prostych są klasy oraz zakresy znakowe.
Zakresy znakowe są definiowane za pomocą wyrażeń nawiasowych. Do ujęcia zakresu stosuje się nawiasy
kwadratowe, a znaki wyznaczane do odszukania mogą być wskazywane bezpośrednio lub poprzez notację
zakresu. Spójrzmy na kilka przykładów:
"[abd]" Dopasowany zostanie łańcuch zawierający literę "a", "b" lub "d".
"[a-z]" Dopasowane zostaną pojedyncze, małe litery od "a" do "z".
"[0-9]" Dopasowane zostaną wszystkie pojedyncze cyfry.
Zakresy można łączyć, budując w ten sposób bardziej złożone wyrażenia:
"[a-zA-Z]" Dopasowana zostanie pojedyncza litera, mała lub wielka.
"[a-zA-Z0-9]" Dopasowany zostanie dowolny znak alfanumeryczny.
W podobny sposób, umieszczając znak karata, '^', jako pierwszy w nawiasie kwadratowym, możemy określać
zakresy znaków, które chcemy wykluczyć z dopasowywania. Postarajmy się nie denerwować faktem, że w tym
przypadku zastosowanie znaku karata jest zupełnie inne, niż omówione poprzednio. Jeśli nas ta odmiana nie
zniechęci (a nie powinno), może jedynie wzmocnić nasze siły.
"[^a-zA-Z]" Dopasowany zostanie dowolny znak nie będący literą.
"[^a-zZ-Z0-9]" Dopasowany zostanie dowolny znak, oprócz alfanumerycznych.
Musimy jeszcze poświęcić chwilę symbolowi '-' używanemu w definicjach zakresów, gdyż ma on znaczenie
specjalne — identyfikuje on zakres (taki jak [a-z] czy [0-9] ).
Aby użyć myślnika jako elementu zakresu znaków, należy upewnić się, że jest on pierwszym znakiem za
nawiasem otwierającym (lub za znakiem karata, jeśli zostanie użyty) lub ostatnim, przed nawiasem
zamykającym.
A zatem, chcąc odszukać dowolny łańcuch ze znakiem alfanumerycznym, poprzedzającym znak myślnika,
powinniśmy użyć jednego z poniższych wyrażeń:
"[a-zA-Z0-9-]"
"[-a-zA-Z0-9]"
Klasy znakowe działają podobnie, ale są znacznie użyteczniejsze niż zakresy. Dzięki ich zastosowaniu możemy
zaoszczędzić sporo czasu, który musielibyśmy poświęcić na konstruowanie wyrażeń z wykorzystaniem innych
technik.
Oto wykaz najbardziej użytecznych klas znakowych:
Klasa znakowa
Dopasowuje...
Znaczy to samo, co
[[:alpha:]]
dowolną literę
[a-zA-Z]
[[:digit:]]
dowolną cyfrę
[0-9]
[[:alnum:]]
dowolną literę lub cyfrę [a-zA-Z0-9]
[[:space:]]
dowolny znak pusty
[ \t\r\n\c]
5
Zgłoś jeśli naruszono regulamin