Programowanie w języku PHP

Wyrażenia Regularne (Regular Expression)

  • 2012-05-21 14:57
  • 17 komentarzy
  • 38486 odsłon
  • Oceń ten tekst jako pierwszy
Ten artykuł wymaga dopracowania!

Jeżeli możesz popraw ten artykuł według zaleceń, które możesz znaleźć na stronie Artykuły do poprawy. Po dopracowaniu tego tekstu można usunąć ten komunikat.



Jak opisać łańcuch ?

Najprostszą metodą jest wypisanie jego wszystkich znaków po kolei. Do takiego opisu pasuje dokładnie jeden łańcuch :-) Czasami jednak zachodzi potrzeba opisu bardziej ogólnego do którego pasowało by ich więcej. Dlatego właśnie wymyślono wyrażenia regularne, które w PHP stosować można w funkcjach ereg(), eregi(), ereg_replace(), eregi_replace(), split(), spliti().

Zacznijmy od podstaw.

W wyrażeniach regularnych stosujemy dwa rodzaje znaków:
  • zwyczajne czyli takie jak np.:
ad4si

  • niezwyczajne
^$*+?.()[]{}\

które wprowadzają do sformułowania regularność :-) Jeżeli chcemy by któryś z 'niezwyczajnych' znaków stał się 'zwyczajnym' to poprzedzamy go ukośnikiem, np.: \\*, \\., \\\ (a to ostatnie to zwyczajny ukośnik :-)).

Jako że wyjaśniliśmy sobie wszystko o znakach, a znaki 'zwyczajne' nie są zbyt interesujące, przejdźmy do tych drugich. Do najważniejszych jak na początek można zaliczyć ., *, +, ?.

Kropka czyli . oznacza w zapisie regularnym jeden dowolny 'zwyczajny' znak. np.:

    r.k - pasuje do słów rak, rok, ryk itd...
    .a. - mak, rak, lat itd...
    .o.a - lola, wola, Cola, rola, kolanooooo !!! Zonk ...?.!!?.!???? :-) hehe

Z tym kolanem to nie błąd. Należy zwrócić uwagę, że sformułowanie .o.a opisuje cztery znaki jednak nie mówi nic o tym co może znaleźć się przed lub po nich. Jeżeli chcemy sobie ustalić w naszym opisie, że jakieś wyrażenie ma się znajdować na początku łańcucha, musimy poprzedzić je daszkiem ^, natomiast to co stoi przed dolarem $ jest traktowane jako koniec ciągu znaków.

Powróćmy do przykładu. Jeżeli chcemy by nasze wyrażenie regularne opisywało dokładnie cztery znaki, powinniśmy zapisać je tak:

    ^.o.a$ - mola, pola itd... (ale nie pagoda czy kolaboracja !!!)

Gwiazdka * opisuje dowolną ilość tego co przed nią stoi. np.:

  mu* - mu , muu, muuuu, muuuuuuuu (czyli tak jak robi krowa :-))
  c.*l - caat, cut, ct, cool, coooool, coooooooooooooooool itd..

A teraz drobne wyjaśnienie. Pisząc 'to co przed nią stoi' mam na myśli:
- pojedynczy 'zwyczajny' znak czy jak w ostatnim przykładzie kropkę '.'
- kawałek wyrażenia w nawiasach okrągłych czyli tzw. atom (ale o tym później)
- zakres znaków znajdujących się w nawiasach kwadratowych (także później :-))

Plus + ma znaczenie takie jak gwiazdka ale z zastrzeżeniem - przynajmniej raz, natomiast znak zapytania ? oznacza, że to co przed nim występuje może pojawić się tylko raz lub w ogóle.

Myślę że teraz można by przejść do nawiasów klamrowych. Ich działanie można by porównać do bardziej zaawansowanego działania gwiazdki, plusa i pytajnika. W nawiasie klamrowym podajemy dokładną liczbę powtórzeń tego co stoi przed nim. Możemy także podać dwie liczby oddzielone przecinkiem, co oznacza powtórzenie wyrażenia minimalnie tyle razy ile pierwsza liczba, a maksymalnie tyle ile druga.

    {3} - dokładnie trzy razy
    {2,4} - minimalnie dwa, a maksymalnie cztery razy
    {5,} - przynajmniej pięć razy

Nieszczęsne nawiasy :-)

W wyrażeniu regularnym możemy pewne jego części umieszczać w nawiasach okrągłych. (tzw. Atom) Ma to taki sam cel jak w zapisie matematycznym. Chodzi o to by działanie jakiegoś 'niezwyczajnego' znaku wpływało na większą część wyrażenia, np.:

    ^.8.{2}(4.{2}){2}$  

Taki zapis oznacza że na początku ma wystąpić jeden dowolny znak ^., potem ósemka i dokładnie dwa dowolne znaki 8.{2}, no i oczekiwane wyrażenie w nawiasie (czyli czwórka i dwa dowolne znaki 4.{2}) które ma wystąpić dwa razy (4.{2}){2} w ten sposób kończąc cały przykład $. Tak się składa że pasuje on dokładnie do łódzkiego telefonu radia taxi 0800400400, ale ciąg t8pq4794j0 także spełni warunek.

Drugim typem nawiasów są nawiasy kwadratowe czyli zakresy. Podaje się w nich zestaw znaków mogących wystąpić w danym miejscu, np.:

    [akj]{5}

Wyrażenie opisuje pięcioliterowy wyraz złożony tylko i wyłącznie z liter 'a', 'k' i 'j', czyli może to być kakak, jjjjj, jakaj, kajka lub po prostu kajak :-) W nawiasach kwadratowych można także podać przedział znaków. Robi się to poprzez wpisanie dwóch znaków oddzielonych myślnikiem. Ważne jest by znakowi przed myślnikiem odpowiadał mniejszy kod Asci od znaku po nim, np:

    [A-Z] - duże litery,  
    [a-z] - małe litery,  
    [0-9] - cyfry

Tak zdefiniowane przedziały literowe nie zawierają polskich znaków. Jeśli chcemy takowe uzyskać najlepiej jest je wszystkie wypisać.

  [0-9a-zA-ZąćęłńóśźżĄĆĘŁŃÓŚŹŻ] - taki zestaw znaków obejmuje wszystkich cyfry,
  małe i duże litery oraz małe i duże polskie znaki

Jeśli w przedziale potrzebny jest znak myślnika, który normalnie używany jest do określania przedziałów znaków, to trzeba umieścić go na pierwszej lub ostatniej pozycji w nawiasach kwadratowych.
W PHP stosować można także 'character classes' czyli już zdefiniowane zbiory znaków:

    [[:alpha:]] - wszystkie litery
    [[:alnum:]] - wszystkie litery oraz cyfry
    [[:digit:]] - cyfry
    [[:xdigit:]] - liczby w systemie szesnastkowym
    [[:lower:]] - małe litery
    [[:upper:]] - duże litery
    [[:punct:]] - znaki interpunkcji

Znak ^ wpisany na pierwszym miejscu wewnątrz nawiasów kwadratowych oznacza negację całego zakresu, np.:

    ^k.*[^w]a$ - reguły tego wyrażenia mogą spełniać słowa kora, koala, kura ale pewne niecenzuralne słowo ich nie spełnia :-))))
    [^0-9]* - tutaj regułą jest by nie pojawiła się żadna cyfra

W wyrażeniach regularnych pomiędzy atomami, znakami lub zakresami można postawić znak '|', który oznacza logiczną operację 'OR', czyli po prostu oznacza że może wystąpić to co znajduje się przed nim lub po nim.

Jakiś przykład zastosowania, żeby nie było że nie ma :-)

Przypuśćmy że na naszej stronie odwiedzający podają w polu input o nazwie 'url' adres jakiegoś pliku w sieci. Chcemy by jego nazwa zaczynała się od http lub ftp, była w domenie pl lub com i żeby plik był w formacie htm, html lub txt. Oprócz tego nie życzymy sobie w adresie żadnych znaków oprócz cyfr oraz liter małych i dużych bez polskich znaków.
Posłużymy się funkcją eregi() która nie zwracając uwagi na wielkość liter porównuje dwa łańcuchy i sprawdza czy pierwszy znajduje się w drugim. Jeżeli 'tak' - zwraca 'true'.
  $url = trim($url);   
  if(eregi("^(ft|htt)p://([a-z0-9]+\\.)+(pl|com)/([a-z0-9]+/)*[a-z0-9]+\\.(html?|txt)$", $url)) 
    jakaś_funkcja_co_zapisuje_url($url);
  else
    echo "Podana nazwa pliku nie spełnia żądanych warunków !";

Wreszcie koniec :-)

Mam nadzieję że mój pierwszy w życiu artykuł przybliżył jakoś temat wyrażeń regularnych. W następnej kolejności napiszę coś więcej o stosowaniu ich w funkcjach PHP w celu wyciągania np. z kodów źródłowych stron interesujących nas informacji czy zamienianiu w długich tekstach określonych sformułowań na inne. Teraz to już koniec :-)

  pozdrawiam...
  Mateusz Piechnat

17 komentarzy

barkurek 2015-02-02 03:45

Super artykuł! Dziękuję!
Wyjaśnienie niezbędne bardzo początkującym takim jak ja, bo długo się samemu do tego dochodzi...: Kiedy widzimy "na piśmie" ukośniki odwrotne dwa (w przypadku tego artykułu tam gdzie pokazano kasowanie "specjalności" jakiegoś znaku, np. kropki), to pisząc to w swoim kodzie stosujemy  tylko jeden.

[losowa nazwa] 2010-01-27 23:12

to jest chyba bledne ?

  "c.*l" - caat, cut, ct, cool, coooool, coooooooooooooooool itd..

Jak dopasujesz slowa konczace sie na "t" ?

psychob 2008-10-01 20:57

Wreszcie normalny artykuł o RegEx, coś się z niego nauczę xD

Patyk 2005-06-05 13:05

Wyśmienity artykuł, tylko o \'+\' powinieneś więcej napisać...

Marooned 2005-06-05 21:17

No i przydałby się opis pełnej notacji perla, czyli (?:) i inne tego typu przydatne rzeczy :)
Jeśli ktoś szuka full wypas opisu pełnej notacji zapraszam na genialną stronę:
http://www.regular-expressions.info

Speedy 2004-08-21 09:57

Dla mnie bomba. Zawsze chciałem poznać te wyrażenia...

Wolverine 2004-08-03 18:09

preg* to wyrazernia regularne perla (podobno szybsze)

Ludomir 2004-07-11 22:19

bardzo dobry artykuł. nareszcie nauczylem sie tych wyrazen!
ale mam jedną uwage: wyrażeń regularnych można uzywac tez w funkcjach preg_, np. preg_match(), preg_replace(), itd...
ale ogólnie umie gosć nieźle tłumaczyć.

Marooned 2004-01-21 00:42

Jak mogłem pominąć ten art :)

Dryobates 2003-07-19 17:35

Super! Tylko tam gdzie jest mu* jeszcze m dodaj :)

piechnat 2003-06-09 23:42

masz świętą racje, a poza tym skąd ja to caaat wziąłem a nie caaal :-) całe to badziewie do poprawki...

problem w tym że, poprawienie tego na tym forum jest dosyć trudne, długo się grzebałem za nim porobiłem wszystkie slashe przed średnikami i itp... jak bym teraz to edytował to by się jeszcze więcej błędów zrobiło ;-( może w coyote będzie lepiej albo jak masz ochotę to sam spróbuj to poprawić ;-p

Vogel 2003-06-09 23:25

 "c.*l" - caat, cut, ct, cool, coooool, coooooooooooooooool itd..
 
Zmieniłbym ten przykład - sugeruje on, że * sygnalizuje wystąpienie dowolnej liczby takich samych elementów, a to przecież nieprawda.

casdaqw412$!@#!tllllll też spełnia warunek :)

Przybek 2003-03-27 16:21

dzięki temu artowi nauczyłem się wyrażeń regularnych... bardzo dobry text! dzięki dla autora!

dchcorp 2003-02-20 19:03

Swietny i tyle

Michał 2003-02-10 14:17

Bardzo dobry artykuł :) Wiele się można nauczyć :D Polecam !!

DarkSpirit 2004-04-13 00:50

Prosto, zabawnie i na temat :)