Wyrażenia regularne – łatwiejsze niż myślisz

Wyrażenia regularne bardzo często są wykorzystywane w programowaniu serwisów internetowych, nie tylko w PHP. Sam termin brzmi poważnie, lecz tak na prawdę wyrażenia regularne nie są niczym więcej jak tylko wzorcem, z którym porównywane są dane. Najczęściej jest to robione w celach walidacji np adresu mailowego albo kodu pocztowego, zamiany tekstu na podstawie danego wzorca, w pliku .htaccess oraz wielu innych przypadkach.

Wyrażenia regularne są dosyć łatwe. Posiadają pewne podstawowe elementy, z których układamy konkretny wzorzec. Skupię się na najważniejszych elementach, które w zupełności powinny wystarczyć większości programistów. Rozróżniamy trzy rodzaje elementów:

  • zamienniki
  • elementy sterujące
  • przełączniki

Nazwy tych trzech rodzai elementów mogą się różnić od nazw stosowanych przez innych, dlatego nie sugerujcie się nimi zbytnio. Najważniejsza jest rola, jaką odgrywają.

Zamienniki

Zamienniki są to elementy, które są używane zamiast określonych grup znaków. Znacznie ułatwiają pracę i dzięki nim wyrażenia regularne są znacznie krótsze, a co za tym idzie – łatwiejsze do rozwikłania. Oto lista zamienników:

  • . – dowolny znak (za wyjątkiem znaków nowej linii – \n \r)
  • \d – liczby
  • \D – odwrotność \d, czyli wszystko co nie jest liczbą
  • \s – białe znaki (spacja, tabulacja itp)
  • \S – odwrotność \s
  • \w – litery, liczby i podkreślenie
  • \W – odwrotność \w

Bardzo często są przypadki, że potrzebujemy określić, że w danym miejscu będą różne znaki, lecz nie jesteśmy w stanie określić kolejności w jakiej wystąpią. Doskonałym przykładem takiego przypadku jest adres mailowy.

Aby go opisać, potrzebujemy grupę znaków, z których parser wybierze sobie te, które akurat potrzebuje. Taką grupę tworzymy przez zawarcie wybranych elementów lub poszczególnych znaków w nawiasach kwadratowych.

Wielu w tym momencie pomyślało zapewne o wypisywaniu w nawiasach całego alfabetu. Nie ma takiej potrzeby. Wystarczy zawrzeć w grupie zakres liter, które nas interesują (od pierwszej do ostatniej). To samo tyczy się cyfr.

Oczywiście nie można zapominać o jednej rzeczy. Wyrażenia regularne są bardzo czułe na punkcie wielkości liter o ile nie użyjemy przełącznika „i”. a teraz parę przykładów grup znaków:

  • [c-k] – ten zapis oznacza wybranie małych liter od c do k
  • [1-7] – tutaj zostaną wybrane liczby od 1 do 7
  • [0-9] – należy pamiętać, że system liczy zawsze od 0, więc w tym przypadku zostaną wybrane wszystkie liczby (od 0 do 9) – to samo co \d
  • [a-zA-Z\d] – jak już pisałem wcześniej, system jest wrażliwy na wielkość liter, więc jeśli chcemy wybrać małe litery i duże litery, to należy je wszystkie wyszczególnić
  • [\da-fA-F] – ten prosty zapis definiuje jeden znak – liczbę w kodzie heksadecymalnym
  • [^a-zA-Z\d] – jeśli chcemy zdefiniować wszystkie znaki prócz wybranych, wystarczy te niechciane zawrzeć w grupie i  na początku dać element sterujący „^”.

Elementy sterujące

Elementy sterujące określają działanie parsera. Konkretnie chodzi o to, co parser ma zrobić z podanymi znakami lub grupami znaków. Oto one:

  • / – w tych elementach jest zamykane wyrażenie regularne
  • ^ – początek dopasowywanego stringa (w grupach negacja)
  • $ – koniec dopasowywanego stringa
  • (myślnik) – używany do określania zakresu elementów w grupie znaków
  • ? – wystąpienie danego elementu zero lub jeden raz
  • * – wystąpienie danego elementu zero lub więcej razy
  • + – wystąpienie danego elementu co najmniej jeden raz
  • {2} – powtarzanie danego elementu dwa razy
  • {2,} – powtarzanie danego elementu co najmniej dwa razy
  • {,2} – powtarzanie danego elementu maksymalnie dwa razy
  • () – grupowanie elementów np do powtórzenia lub jako atrybut do zamiany
  • | – oddzielenie opcji do wyboru w grupach elementów (opcja1|opcja2|…)

Należy pamiętać, że nie możemy bezkarnie używać elementów sterujących w grupowaniu znaków (nawiasy kwadratowe). W najlepszym wypadku wyrażenie regularne nie zostanie dopasowane, a w najgorszym, skrypty zaczną sypać błędami.

Aby temu zapobiec, należy stosować „\” przed każdym elementem sterującym. Jeśli chodzi o myślnik, to nie ma konieczności stosowania backslasha, ale tylko w przypadku, kiedy myślnik jest ostatnim znakiem w grupie znaków.

Przełączniki

Przełączniki również można uznać za elementy sterujące, jednak znajdują się one poza wyrażeniem. Zasięgiem obejmują całe wyrażenie regularne (niezależnie od grupowania itd). A oto one:

  • i – brak wrażliwości na wielkość liter
  • U – wyłączanie zachłanności dla wyrażeń regularnych (UnGreedy)
  • g – szukanie i zamiana w całym stringu (w PHP jest domyślnie włączony)

Edit:
Zapomniałem o jeszcze jednym ważnym przełączniku – mianowicie chodzi o przełącznik s. Oznacza on, że znak kropki będzie również brać pod uwagę znaki nowej linii (\n \r).

Przykłady łatwych wyrażeń regularnych

  • kod pocztowy – /^\d{2}-\d{3}$/
  • NIP – /^\d{3}-(\d{3}-\d{2}|\d{2}-\d{3})-\d{2}$/
  • adres mailowy /^[\wąćęłńóśźżĄĆĘŁŃÓŚŹŻ-]+(\.[\wąćęłńóśźżĄĆĘŁŃÓŚŹŻ-])*@([\wąćęłńóśźżĄĆĘŁŃÓŚŹŻ-]\.)+[a-z]{2,7}$/i

Testery wyrażeń regularnych

W internecie jest wiele stron oferujących testery do wyrażeń regularnych. Ja najczęściej używam jednej regexpal.com. Umieszczony tam tester posiada wiele przydatnych rzeczy:

  • ściągawka (bardzo przydatna dla początkujących)
  • kolorowanie składni zarówno dla całego wyrażenia jak i każdej grupy elementów
  • pokazywanie dopasowanego wyrażenia regularnego do podanego tekstu

Jeśli potrzebujecie więcej stron z testerami, to proponuje poszukać na grupach dyskusyjnych lub w wyszukiwarkach. Kładę tutaj nacisk na SZUKAĆ, a nie pytać! Zdecydowana większość pytań została już zadana, a odpowiedzi łatwo można znaleźć.

Aby znaleźć daną frazę tylko na wybranej stronie wystarczy wpisać:

fraza site:blogwebmastera.pl

Jak widzicie, wyrażenia regularne mają trochę elementów, jednak nie jest to aż tak trudne do zapamiętania jak się wydaje. Na początku części rzeczy i tak pewnie nie będziecie wykorzystywać. W wyrażeniach regularnych najczęściej wykorzystywane są zamienniki oraz elementy sterujące. To właśnie ich powinniście się nauczyć w pierwszej kolejności.

Jak już ktoś pojmie o co tutaj chodzi, to podczas programowania witryn internetowych, bez problemu sobie poradzi z tworzeniem wyrażeń regularnych i nawet nie będzie potrzebować ściągi.

Na tym blogu o programowaniu WWW w artykułach nie raz będę wracać do wyrażeń regularnych, więc dobrzy by było, gdybyście się ich nauczyli. Na pewno wyjdzie to Wam na dobre.

Jak będziecie potrzebować jakieś przykłady gotowych wzorców, to piszcie w komentarzach. Postaram się jak najszybciej na nie odpowiadać.

Twitter Obserwuj mnie na Blip.pl 

Komentarzy: 7

drizztt
26 stycznia 2013 o 21:00

Witam potrzebował bym wzór:
– na pierwszej pozycji liczba 0-9 lub znak –
– potem liczby lub jedno wystąpienie znaku , lub .
– ostatnia musi być liczba
np 1; -1; 1.1; -1,234; 12,345 itp.
Proszę o pomoc.

Miwol
28 stycznia 2013 o 13:24

Z tego co widzę, jest to bardzo prosta walidacja liczb. Według mnie zamiast angażować do tego wyrażenia regularne, lepiej użyć prostego triku.

if(($liczba*1).''==$liczba){
  echo 'Wartość prawidłowa';
}else{
  echo 'Wartość błędna';
}

W tym krótkim warunku jest wykonywanych kilka operacji:

  • mnożymy $liczba przez 1, żeby otrzymać typ liczbowy (konwersja w locie)
  • do wyniku dodajemy pustego Stringa, dzięki czemu nastąpi konwersja w locie do typu String
  • na końcu porównujemy dwa Stringi.

Przed walidacją dobrze jest zdecydować się na jeden format (1.1 lub 1,1). Dlatego przed porównywaniem należy zamienić przecinek na kropkę lub odwrotnie.

Na koniec napiszę też wyrażenie regularne, które będzie przeprowadzać tę walidację.

^-?\d+(\.\d+)?$

Na zapas napiszę też wytłumaczenie wyrażenia, podzielone na kawałki, by łatwiej było je zrozumieć:

  • ^ – początek tekstu
  • -? – ten fragment odpowiada za sprawdzanie czy na początku jest minus; znak zapytania oznacza, że minus jest opcjonalny
  • \d+ – co najmniej jedna cyfra
  • (\.\d+)? – wartość po przecinku; jest to zamknięte w nawias ze znakiem zapytania na końcu, co oznacza, że całość jest opcjonalna
  • $ – zakończenie tekstu.
Hubert G
3 stycznia 2014 o 14:30

Witam
Mam problem z zamianą w Notepad++ danego ciągu znaków w kilkudziesięciu plikach
a mianowicie dokładniej
w pliku pierwszym jest ciąg

PL.PRACA.HUB.123.10

w pliku drugim jest ciąg

PL.PRACA.AGA.123.10

w pliku trzecim

PL.PRACA.OLA.123.10

itd

Potrzebuję w każdym pliku dodać dany ciąg (999) przed ostatnimi cyferkami
aby w pliku pierwszym zamieniło się na

PL.PRACA.HUB.123.99910

w pliku drugim zamieniło się na

PL.PRACA.AGA.123.99910

w pliku drugim zamieniło się na

PL.PRACA.OLA.123.99910

teoretycznie proste ale za trudne dla mnie
proszę o podpowiedź

Miwol
3 stycznia 2014 o 14:41

Rzeczywiście to jest proste, ale nie każdy jest obeznany z wyrażeniami regularnymi w edytorach tekstu.
W Notepad++ obowiązują te same zasady co w zwykłych wyrażeniach. Dotyczy to również grupowania.
Jedyna różnica jaka jest pomiędzy tym programem, a językami programowania jak np PHP, czy JavaScript to wywołanie grup.
Normalnie wywołuje się grupy za pomocą znaku „$” np „$1”, „$2” itp.
W edytorze Notepad++ grupy wywołuje się za pomocą znaku „\” np „\1”, „\2” itp.

W tym przykładzie we frazie wyszukiwanej zamykamy w grupy to co ma być przed „999” i to co ma być po „999”.
Grupa pierwsza to będzie „PL.PRACA.HUB.123.”, a grupa druga to „10”.
We frazie do zamiany wpisujemy wywołanie grup, a pomiędzy nimi to co chcemy dodać, czyli „999”.

Fraza wyszukiwana:

(PL\.PRACA\.[A-Z]{3}\.\123\.)(10)

Fraza do zamiany:

\1999\2

Jeśli nie jesteś pewien, czy numery zawsze będą takie same, to zamiast numerów lepiej dać \d+.

Hubert G
7 stycznia 2014 o 07:57

Dziękuję Ci za odpowiedź ale jakoś mi to nie działa. Może jakaś literówka w tym jest?? Ciężko mi to sprawdzić nie znając się na tym.

Hubert G
7 stycznia 2014 o 08:04

Już działa, jeszcze raz dziękuję za odpowiedź.

przepisywanie
10 lutego 2014 o 07:58

nareszcie mi coś działa dzięki tym prostym czytelnym wskazówkom.

Dodaj komentarz

Twój komentarz

CommentLuv badge