Wiele wyrażeń specjalnych, takich jak + i |, wpływa na dopasowanie „czegoś” po swojej lewej lub prawej stronie. Na ogół tym czymś jest pojedynczy znak, wzorzec podrzędny ujęty w nawiasy okrągłe lub kategoria znaków ujęta w nawiasy kwadratowe. Jeśli jednak chodzi o znak |, jego działanie rozciąga się w nieskończoność zarówno na lewo, jak i na prawo. Jeśli chcesz ograniczyć zasięg działania pionowej kreski, ujmij ją wraz z jej elementami w nawiasy okrągłe, np.:

Ja jestem (jajcarz|morsem)\.

odpowiada zarówno zdaniu „Ja jestem jajcarz.”, jak i „Ja jestem morsem.”. W tym przykładzie zademonstrowano również unikanie znaków specjalnych (w tym przypadku kropki). Wzorzec:

(Ja jestem (jajcarz|morsem)\. ?){1,2}

odpowiada każdemu z poniższych wyrażeń:

Ja jestem morsem.
Ja jestem jajcarz.
Ja jestem morsem. Ja jestem jajcarz.
Ja jestem jajcarz. Ja jestem morsem.
Ja jestem jajcarz. Ja jestem jajcarz.
Ja jestem morsem. Ja jestem morsem.

Odpowiada to również wyrażeniu „Ja jestem morsem. Ja jestem jajcarz. Ja  jestem morsem.”, mimo że liczba powtórzeń została wyraźnie ograniczona do dwóch. Jest to spowodowane tym, że wzorzec nie musi pasować do całego przeszukiwanego tekstu. W tym przypadku wyrażenie regularne znajdzie dwa pasujące zdania i przerwie działanie, zgłaszając sukces. To, że występuje tu jeszcze jedno powtórzenie, nie będzie miało żadnego znaczenia. Częstym błędem jest mylenie metaznaku wyrażenia regularnego * (zero lub więcej wystąpień) z symbolem wieloznacznym powłoki, *. Wersja gwiazdki używana w wyrażeniach regularnych musi mieć podany element do zmodyfikowania; w przeciwnym razie nie zrobi tego, czego oczekujesz. Jeśli dopuszczalnym dopasowaniem ma być dowolna sekwencja znaków (w tym również brak jakiegokolwiek znaku), zastosuj wyrażenie .*.

Przykłady wyrażeń regularnych:
Kody pocztowe w Stanach Zjednoczonych składają się z albo tylko pięciu cyfr, albo z pięciu cyfr, po których następuje myślnik i kolejne cztery cyfry. Aby utworzyć wyrażenie regularne dla zwykłego kodu, musisz dopasować pięciocyfrowy numer. Można to wyrazić przez:

^\d{5}$

Znaki ^ i $ oznaczają początek i koniec szukanego tekstu, ale nie odpowiadają żadnym znakom w tekście; są to „wyznaczniki o zerowej szerokości”. Znaki te dają pewność, że wyrażeniu regularnemu odpowiadać będzie tylko tekst składający się dokładnie z pięciu cyfr — w tym przypadku wyrażenie regularne nie dopasuje pięciu cyfr wewnątrz większego ciągu. Wyrażenie \d oznacza cyfrę, a kwantyfikator {5} mówi, że musi wystąpić dokładnie pięć cyfr. Jeśli wyrażenie regularne ma obejmować zarówno kod pięciocyfrowy, jak i kod rozszerzony o kolejne cztery cyfry, musisz dodać opcjonalny myślnik i cztery dodatkowe cyfry:

^\d{5}(-\d{4})?$

Nawiasy okrągłe grupują razem myślnik i dodatkowe cyfry, dzięki czemu są one traktowane jako jeden opcjonalny element. Takie wyrażenie regularne nie wychwyci np. pięciocyfrowego kodu, po którym występuje myślnik. Jeśli obecny jest myślnik, musi również wystąpić czterocyfrowe rozszerzenie, w przeciwnym razie nie będzie dopasowania. Klasycznym przykładem dopasowania za pomocą wyrażeń regularnych jest wzorzec:

M[ou]'?am+[ae]r\s([AEae]l[-\s])?[GKQ]h?[aeu]+([dtz][dhz]?){1,2}af[iy]

który odpowiada większości wariantów pisowni imienia i nazwiska przywódcy Libii, Muammara al-Kaddafiego, włącznie z takimi jak:

Muammar al-Kaddafi (BBC),
Moammar Gadhafi (Associated Press),
Muammar al-Qadhafi (Al-Jazeera),
Mu’ammar Al-Qadhafi (Departament Stanu USA).

To wyrażenie regularne pokazuje również, jak szybko można przekroczyć granice czytelności. Wiele systemów korzystających z wyrażeń regularnych obsługuje opcję x, która ignoruje dosłowne puste znaki we wzorcu i umożliwia stosowanie komentarzy, dopuszczając rozdzielanie poszczególnych elementów i podział na wiele wierszy. Możesz wtedy wstawić puste znaki, aby oddzielić od siebie grupy logiczne i sprawić, że ich wzajemne związki staną się czytelniejsze, tak samo, jak zrobiłbyś to w języku proceduralnym. Dla przykładu przedstawiamy bardziej czytelną wersję tego samego wyrażenia regularnego dotyczącego Muammara al-Kaddafiego:

M [ou] '? a m+ [ae] r # Imię: Mu’ammar, Moamar, itd.
\s # Znak pusty; nie można tu użyć dosłownej spacji
( # Grupa dla opcjonalnego prefiksu przed nazwiskiem
[AEae] l # Al., El, al lub el,
[-\s] # po którym występuje myślnik lub spacja
)?
[GKQ] h? [aeu]+ # Początkowa sylaba nazwiska: Kha, Qua, itd.
( # Grupa dla spółgłosek na początku drugiej sylaby
[dtz] [dhz]? # dd, dh, itd.
){1,2} # Grupa może wystąpić dwukrotnie, jak w Quadhdhafi
af [iy] # Końcowe afi lub afy

To nieco pomaga, ale wciąż dość łatwo doprowadzić do sytuacji, w której lektura Twojego kodu będzie dla innych torturą. Dlatego dbaj o czytelność: jeśli możesz, stosuj dopasowywanie hierarchiczne i wiele mniejszych dopasowań zamiast próby objęcia wszystkich możliwych sytuacji w jednym dużym wyrażeniu regularnym.

Przechwytywanie:
Gdy dopasowanie zakończy się powodzeniem, każdy zestaw nawiasów staje się „grupą przechwytującą”, która zapisuje odpowiadający mu rzeczywisty tekst. Dokładny sposób udostępniania tych fragmentów zależny jest od implementacji i kontekstu. W większości przypadków dostęp do wyników dopasowania można uzyskać w formie listy, tablicy lub sekwencji ponumerowanych zmiennych. Ponieważ nawiasy mogą być zagnieżdżane, skąd będziesz wiedzieć, które dopasowanie jest które? To proste: dopasowania pojawiają się w tej samej kolejności, co nawiasy otwierające. Istnieje tyle przechwyceń, ile jest nawiasów otwierających, bez względu na rolę (lub jej brak), jaką każda ujęta w nawiasy grupa odgrywa w rzeczywistym dopasowywaniu. Jeśli jakaś grupa w nawiasach nie jest używana (np. Mu(‚)?ammar przy dopasowywaniu do łańcucha „Muammar”), odpowiadające jej przechwycenie jest puste. Jeśli grupa jest dopasowywana więcej niż jeden raz, zwracana jest zawartość tylko ostatniego dopasowania. I tak gdy wzorzec:

(Ja jestem (morsem|jajcarz)\. ?){1,2}
dopasujemy do tekstu:
Ja jestem jajcarz. Ja jestem morsem.
otrzymamy dwa wyniki, po jednym dla każdej pary nawiasów:
Ja jestem morsem.
morsem

Obie grupy są dopasowywane dwukrotnie, jednak z każdej pary nawiasów przechwycony
zostaje tylko ostatni pasujący tekst.

Wyrażenia regularne są dopasowywane od lewej do prawej. Do każdego składnika wzorca dopasowywany jest najdłuższy możliwy łańcuch, a dopiero potem następuje przejście do kolejnego składnika. Takie zachowanie określamy mianem zachłanności (ang. greediness). Jeśli wyrażenie regularne dochodzi do stanu, w którym dopasowanie nie może zostać zakończone, odbiera kawałek poprzedniego dopasowania i sprawia, że jeden z elementów zachłannych oddaje część swojego tekstu. Aby to zademonstrować, rozważmy przykład, w którym wyrażenie regularne a*aa jest dopasowywane do tekstu wejściowego „aaaaaa”.
Na początku całe wejście przypisywane jest do części a* wyrażenia regularnego, ponieważ a* jest wyrażeniem zachłannym. Gdy nie ma już więcej liter a, następuje próba dopasowania następnej części wyrażenia regularnego. Ale co to? Następny element to a, a nie ma już  więcej tekstu wejściowego, który można by przypisać do a, trzeba się więc wycofać. Wyrażenie a* musi oddać jedną ze swoich liter a, które zostały mu przypisane. Teraz można już dopasować wyrażenie a*a, ale wciąż zostaje jeszcze ostatnie a we wzorcu. Następuje więc kolejne wycofanie i przejęcie drugiej litery a z a*. Teraz drugie i trzecie a z wzorca mają już przypisane swoje litery a, można więc zakończyć proces dopasowywania. Ten prosty przykład jest ilustracją pewnych ważnych kwestii. Na początek, przy przetwarzaniu całych plików wyrażenia zachłanne i wycofywanie sprawiają, że dopasowywanie pozornie prostych wzorców w rodzaju <img.*></tr> staje się procesem niezwykle kosztownym18. Do części .* przypisane zostaje wszystko, począwszy od pierwszego wystąpienia łańcucha <img aż do końca wejścia, i tylko powtarzane wycofywanie sprawia, że w końcu udaje się dopasować lokalne znaczniki. Ponadto występujący w tym wzorcu element ></tr> przypisany zostanie do ostatniego wystąpienia tego łańcucha w danych wejściowych, a chyba nie tego chciałeś. Prawdopodobnie chodziło Ci o dopasowanie do znacznika <img>, po którym występuje znacznik </tr>. Lepszym sposobem zapisania takiego wzorca będzie wyrażenie <img[^>]*>\s*</tr>, w którym początkowy symbol wieloznaczny dopasuje łańcuch ciągnący się tylko do końca bieżącego znacznika, ponieważ nie może on przekroczyć granicy wyznaczonej przez zamykający nawias trójkątny. Możesz też używać leniwych (będących przeciwieństwem zachłannych) operatorów wieloznacznych: *? zamiast * oraz +? zamiast +. Te wersje dopasowują możliwie jak najmniejszą liczbę znaków wejściowych. Jeśli to się nie powiedzie, dopasowują następne. W wielu sytuacjach operatory te są bardziej wydajne i bliższe temu, co chcesz uzyskać, niż wersje zachłanne. Zauważ jednak, że mogą zwrócić inne dopasowania niż operatory zachłanne; różnica polega nie tylko na sposobie implementacji. W naszym przykładzie z kodem HTML wzorcem leniwym mógłby być <img.*?></tr>. Ale nawet wtedy element *? mógłby w końcu rozrosnąć się tak, że obejmowałby niechciane znaki >, ponieważ po <img> mógłby występować jeszcze inny znacznik niż </tr>.

ZOSTAW ODPOWIEDŹ

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.