Wyrażaj się regularnie
Definicję wyrażeń regularnych (ang. regular expressions, stąd regex) można zamknąć w paru słowach – są to wzorce i przepisy na ciągi znaków. Do czego się przydają? Do wyszukiwania za jednym zamachem plików o podobnych nazwach/rozszerzeniach, treści w tekście i innych czynności związanych z tekstowym dopasowywaniem zawartości. Brzmi to może nieco wydumanie, bo co można skomplikować w wyszukiwaniu plików? Ale wystarczy przypomnieć sobie ile razy szukaliśmy na dysku np. pliku o rozszerzeniu .jpg… A może to było .png? Kiedy w operacji chcemy uwzględnić kilka wariantów – regex pozwoli dokładniej opisać nierozumnej maszynie zakres naszych oczekiwań. Wystarczy wpleść w nasze zapytanie kilka magicznych kodów i odkryjemy drogę ku nowemu. Jednak temat jest tak rozległy, że nadmiar teorii mógłby wydać się nudny, dlatego – poniżej podstawowe podstawy komunikacji ze światem za pomocą wyrażeń regularnych.
Na początek – gdzie jest koniec
Pierwsze elementy sterujące jakie warto znać, to określenie, czy wyszukiwany przez nas ciąg znaków ma znaleźć się na początku czy na końcu wyrażenia:
- ^ (daszek) rozpoczyna się od – oznacza, że podany ciąg ma znajdować się na początku wyrażenia (np. do wzorca “^tra” będzie pasował traktor, ale już nie mantra),
- $ (dolar) kończy się na – to samo, tylko od końca (czyli, do wzorca “tra$” będzie pasowała mantra, ale już nie traktor)
Jeżeli wzorzec ujmiemy w “^wzór$“, rezultatem będzie tylko i wyłącznie słowo wzór.
Jeden czy więcej, a może wcale
Kolejno możemy określić ilościowe występowanie danych znaków:
- . (kropka) jeden dowolny znak – zastępuje w wyrażeniu dowolny znak (czyli do “traktor.” będzie pasowało traktory, traktora),
- * (gwiazdka) zero lub
nieskończona liczbawięcej wystąpień znaku poprzedzającego – zastępuje w wyrażeniu dowolną liczbę wystąpień znaku wcześniejszego – najczęściej łączone z kropką (np. “^t.*r$” będzie pasowało do traktor, towar, trener, - ? (pytajnik) zero lub jedno wystąpienie znaku poprzedzającego – warunkuje istnienie wcześniejszego znaku (czyli “^traktory?$” oznacza traktor lub traktory),
- + (plus) jedno lub więcej wystąpień znaku poprzedzającego – poprzedzający znak może wystąpić co najmniej raz, lub wiele razy (czyli “^ala+” będzie pasowało dla ala i alaa, lecz nie alaaa)
Zamknięci w nawias
Nawiasy też mają konkretne i interesujące przeznaczenie w wyrażeniach regularnych:
- [ ] jeden ze znaków ujętych w nawias – dopasuje jeden ze znaków wypisany w nawiasie (czyli “^tra[knp]” pasuje do trak, tran, trap). Mamy też możliwość definiowania zakresów znaków np. “[a-z]” oznacza zakres liter od a do z, [0-9] cyfry od zero do 9, itp. Jakby tego było mało, przy użyciu ^ (daszek) włączamy negację (czyli “[^a-z]” – wszystko, oprócz zakresu liter od a do z,
- ( ) grupowanie ciągu znaków – ujęte w nawias wyrażenie dla dalszych machinacji stanowi całość (czyli np. “^(abc)+” dopasuje się do powtórzeń ciągu abcabc),
- { } ilość powtórzeń – liczba powtórzeń znaku poprzedzającego (czyli “^ala{3}” dopasuje alaaa)
Specjalnie i niespecjalnie
Na tym nie koniec uroków zaklinania znaków i wyrażeń. Regex ułatwia elastyczne dopasowanie się do treści, oraz specjalne traktowanie swoich wyjątkowych kodów:
- \ (ukośnik) znosi znaczenie metaznaków – jeżeli zachodzi potrzeba wyszukania znaków, które są jednocześnie kodami sterującymi regex, \ zniesie ich działanie i potraktuje jako zwykły znak (czyli “^Traktor\. Jeden\.$” pasuje do Traktor. Jeden.),
- | (pionowa kreska) warunkowe lub – typowy warunek (czyli “^(aaaa|bbbb)” wyraża aaaa lub bbbb)
Grunt to podstawy
I tak wygląda wprowadzenie w tematykę wyrażeń regularnych. Dla codziennego ułatwiania sobie życia powyższe wywody w większości wystarczą, a każdy kto na poważniej zamierza związać się z wyrażeniami regularnymi powinien poszerzyć swoją wiedzę w oparciu o bardziej kompleksowe opisy regex.
Ale gdzie tego używać? Zacząć można od tekstowych poleceń grep i egrep. To podstawowe narzędzia, które umożliwiają korzystanie z wyrażeń regularnych (UWAGA – grep obsługuje ‘uproszczony’ zasób metaznaków). A po wprawieniu się w konstruowaniu reguł, nie straszny będzie nam żaden innych program.
A poniżej – kilka prostych przykładów…
Kod pocztowy:
[0-9]{2}-[0-9]{3}
Adres email:
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]{1,})*\.([a-zA-Z]{2,}){1}$
Data urodzenia:
^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$/