Wyrażenia regularne są bardzo powszechnie wykorzystywane w programowaniu aplikacji internetowych. Są to wzorce, które dopasowywane są do napisów. Mogą być wykorzystywane np. do weryfikacji poprawności napisów (np. kodu pocztowego, numeru telefonu, nazwiska) ale również do wydostawania pewnych informacji ze złożonych napisów.
Wyrażenia regularne zapisywane są z wykorzystaniem ukośników np. następujące wyrażenie pasuje do napisu zawierającego co najmniej jedną literę 'a'
/a/
Dopasowania napisu do wyrażenia może być weryfikowane na dwa sposoby. Po pierwsze można skorzystać z operatora dopasowania =~
"Ala ma kota" =~ /a/
"Ala ma kota" =~ /x/
Wartość zwracana przy dopasowaniu to indeks pierwszego dopasowanego znaku. Jeśli dopasowanie się nie powiodło zwracana jest wartość nil
. Dzięki temu dopasowanie wyrażeń w tej formie często wykorzystywane jest w instrukcji warunkwej.
Drugi sposób dopasowania to użycie metody match
zdefiniowanej dla wyrażeń regularnych
/a/.match("Ala ma kota")
Dla tej metody zwracany jest jednak nie indeks, ale obiekt klasy MatchData
, który pozwala "odpytać" jak dokładnie wygląda dopasowanie
matched = /a/.match("Ala ma kota")
matched.begin(0)
matched.end(0)
Argument przekazywany do metod begin
oraz end
oznaczna indeks dopasowanej "podgrupy" wyrażenia. Indeks 0 oznaczna
całe dopasowanie.
Jak myślisz, dlaczego w przypadku dopasowania łańcucha do wyrażenia zwracany jest indeks pierwszego dopasowanego znaku, a w przypadku niedopasowania, wartość nil
?
W wyrażeniach regularnych poza zwykłymi znakami występują znaki specjalne
Znak specjalny | Znaczenie |
---|---|
. | dowolny znak |
| | alternatywa |
( | początek podgrupy |
) | koniec podgrupy |
[ | zakres wartości |
{ | krotność |
* | zero lub więcej wystąpień |
+ | jedno lub więcej wystąpień |
? | zero lub jedno wystąpienie |
\ | znak wymazujący znaczenie znaku specjalnego |
^ | początek linii |
$ | koniec linii |
Jeśli chcemy aby te znaki zostały dopasowane bezpośrednio, musimy poprzedzić je odwrotnym ukośnikiem. Poniższe dopasowanie dopasuje się do dowolnego znaku:
"a" =~ /./
Jeśli chcemy dopasować kropkę, musimy użyć odwrotnego ukośnika
"a" =~ /\./
"." =~ /\./
Alternatywa dopasowuje się do wyrażenia po prawej lub wyrażenia po lewej stronie
"mały" =~ /mały|duży/
"duży" =~ /mały|duży/
"wielki" =~ /mały|duży/
Podgrupy pozwalają na wyodrębnianie pewnych informacji z dopasowanego łańcucha. Przykładowo, jeśli z adresu chcemy wyodrębnić kod i miejscowość możemy użyć następującego wyrażenia:
matched = /(\d\d-\d\d\d) (\w+)/.match("00-700 Warszawa, ul. Krótka 5")
matched[1]
matched[2]
Pierwsza dopasowana podgrupa obejmuje kod pocztowy, a druga - nazwę miejscowości.
Napisz wyrażenie, które dopasowuje się do numeru telefonicznego z kodem kierunkowym województwa. Użyj podgrup, aby wydostać kod kierunkowy z pełnego numeru telefonu. Przykładowe numer: "12 2 123 123", "22 23 32 654"
W powyższym przykładzie wykorzystaliśmy tzw. klasy znaków \d
oraz \w
. Klasy te reprezentują grupy znaków, które często pojawiają się w wyrażeniach regularnych. \d
oznacza cyfry dziesiętne, a \w
litery oraz cyfry.
Jeśli chcemy określić, że na danej pozycji może wystąpić jeden spośród kilku znaków możemy skorzystać z własnych klasy znaków. Możemy podać bezpośrednio wszystkie znaki, które mogą być dopasowane na danej pozycji:
"Ala" =~ /[AO]la/
"Ola" =~ /[AO]la/
"Jola" =~ /[AO]la/
Możemy również podać zakres liter bądź cyfr. Należy jednak pamiętać, że zakresy te nie obejmują liter z polskimi znakami diakrytycznymi:
"Ala" =~ /[A-Z]la/
"Óla" =~ /[A-Z]la/
Najczęściej wykorzystywane klasy znaków
Symbol | Znaczenie |
---|---|
. | dowolny znak |
\d | cyfra dziesiętna |
\D | coś innego niż cyfra dziesiętna |
\s | białe spacje |
\S | coś innego niż białe spacje |
\w | litery i cyfry alfabetu łacińskiego |
\W | coś innego niż litery i cyfry alfabetu łacińskiego |
\p{L} | litery różnych alfabetów |
\p{Lu} | duże litery różnych alfabetów |
\p{Ll} | małe litery różnych alfabetów |
Napisz wyrażenie, które dopasowuje się do napisów rozpoczynających się wielką literą. Uwzględnij napisy takie jak: Łódź oraz Żaneta.
W wyrażeniach regularnych często oczekujemy, że określony znak lub grupa znaków pojawi się określoną ilość razy. Można wtedy powtórzyć wystąpienia tych znaków lub grup znaków, jak w przypadku dopasowania kodu pocztowego
"00-700" =~ /\d\d-\d\d\d/
Można jednak zkorzystać z możliwości określenia krotności
"00-700" =~ /\d{2}-\d{3}/
Krotność może być określona "sztywno", bądź może obejmować zakres:
"aaa" =~ /a{2,4}/
"aaaaa" =~ /a{2,4}/
Często oczekujemy, że określone elementy wystąpią zero albo więcej razy. Wykorzystujemy wtedy gwiazdkę
"aabbbcc" =~ /ab*c/
"aacc" =~ /ab*c/
Podobnie działają operatory +
oraz ?
. Pierwszy wymaga jednak, aby dany znak wystąpił co najmniej jeden raz:
"aabbbcc" =~ /ab+c/
"aacc" =~ /ab+c/
Natomiast ?
oznacza, że element jest opcjonalny, tzn. może wystąpić 0 lub 1 raz
"-5" =~ /-?\d+/
"123" =~ /-?\d+/
Napisz wyrażenie, które dopasuje się do kodu pocztowego i nazw miast występujących w Polsce. Uwzględnij fakt, że nazwa miasta powinna zaczynać się wielką literą. Przetestuj działanie wyrażenia na następujących danych testowych:
Ostatnim ważnym elementem pojawiającym się w wyrażeniach regularnych są kotiwce - czyli takie miejsca w napisie, które nie odpowiadają konkretnemu znakowi, lecz pewnej granicy - np. granicy pomiędzy słowem a białą spacją. Do najczęściej stosowanych kotwic należą
Symbol | Znaczenie |
---|---|
^ | Początek wiersza |
$ | Koniec wiersza |
\A | Początek napisu |
\z | Koniec napisu |
\b | granica słowa |
Przykładowo jeśli chcemy dopasować "Ala", ale tylko wtedy gdy pojawia się na początku wiersza, musimy użyć kotwicy:
"Ala ma kota" =~ /^Ala/
"To kot, a to Ala" =~ /^Ala/
Kotwica \b
przydaje się jeśli chcemy np. podzielić napis względem granic słów:
"Ala ma kota".split(/\b/)
Dzięki niej możemy również upewnić się, że dopasowujemy konkretne słowo, a nie literę wewnątrz słowa. Porównaj
"Ania i Kasia" =~ /i/
"Ania i Kasia" =~ /\bi\b/
Napisz algorytm, które z adresu URL wyodrębnia:
Przykładowy adres do testowania: http://www.wp.pl:8080/aktualnosci/krakow/1112.html?id=5#tresc
Powinniśmy otrzymać następujący wynik końcowy:
protokół: http
host: www.wp.pl
port: 8080
ścieżka: /aktualnosci/krakow/1112.html
zapytanie: id=5
fragment: tresc