Wyrażenia regularne mogą wydawać się skomplikowane i enigmatyczne, pełne dziwnych znaczków zrozumiałych tylko dla nielicznych. Jednak są one znacznie prostsze do zrozumienia, niż mogłoby się wydawać. Jako były pracownik uczelni technicznej, mam pewną „awersję” do skomplikowanych matematycznych zapisów, ale wyrażenia regularne są naprawdę przydatne i wcale nie takie trudne do opanowania.
Co to jest wyrażenie regularne?
Wyrażenia regularne to narzędzia służące do opisywania wzorców tekstowych, które chcemy znaleźć w danym ciągu znaków. Mogą one opisywać na przykład daty (np. 21.07.2020), ciągi liczb (np. 2, 4, 22, 26, 31, 35 w Lotto), adresy email, adresy stron internetowych czy też określone znaki w haśle do konta bankowego. Wzorzec może opisywać wszystko, co jest w jakiś sposób powtarzalne. Wyrażenia regularne pomagają nam znaleźć w tekście ciąg znaków pasujący do określonego wzorca.
Koncepcja automatu wyszukującego pasujący ciąg znaków w tekście znana jest od lat 50. XX wieku. Jedna z pierwszych implementacji powstała w języku SNOBOL – z naszej perspektywy nazwa nieco nietrafiona.
Praktyczne zastosowanie wyrażeń regularnych
Wyrażenia regularne są często używane w skomplikowanych systemach informatycznych do wyszukiwania i przetwarzania ciągów znaków oraz do walidacji tekstu wpisanego przez użytkownika. Jednak mogą się również przydać w codziennym użyciu.
Przykład: szukanie dat
Załóżmy, że przeszukujemy stronę Wikipedia w poszukiwaniu osób, które urodziły się jeszcze w XVII wieku i żyły do minimum lat dwudziestych XVIII wieku. Wpisanie „16” w wyszukiwarce daje ponad 100 wyników – przeglądanie tego ręcznie byłoby uciążliwe. Z pomocą przychodzą wyrażenia regularne.
Najprostszym rozwiązaniem jest wykorzystanie strony www.regex101.com. Wklejamy tam całą zawartość strony Wikipedii w pole „TEST STRING” i wpisujemy wyrażenie regularne w pole „REGULAR EXPRESSION”. Wyniki szukania pojawią się po prawej stronie w polu „MATCH INFORMATION”.
Przykładowe wyrażenie regularne do naszego zadania to:
[0-9]{2}–17[2-9][0-9]
Oto co oznaczają poszczególne części wyrażenia:
- 16 – ciąg znaków musi zaczynać się od „16”.
- [0-9]{2} – po „16” oczekujemy dwóch cyfr (np. 1625).
- –17 – po dacie (np. 1625) oczekujemy „-17”.
- [2-9] – w XVIII wieku interesują nas lata powyżej lat dwudziestych (np. 1724, 1735).
- [0-9] – ostatnia cyfra może być dowolna (0–9).
Po wpisaniu tego wyrażenia, otrzymujemy około 20 wyników, znacznie mniej niż przy ręcznym przeszukiwaniu.
Szukanie słów i innych wyrażeń
Przykład wyszukania wszystkich słów:
[a-zA-Ząęźćżłóń]+
Co oznacza to wyrażenie?
- [a-zA-Ząęźćżłóń] – znajdź wszystkie małe i duże litery, w tym polskie znaki.
- + – znak ma się powtórzyć 1 lub więcej razy.
Wynik: około 5641 znalezionych słów.
Przykład wyszukania miejsc, gdzie jest wspomniany lipiec lub luty:
lipc[a-z]*|lut[a-z]*
Co oznacza to wyrażenie?
- lipc[a-z]* – znajdź „lipc” i dowolne litery po nim (np. lipiec, lipca).
- | – oznacza „lub”.
- lut[a-z]* – znajdź „lut” i dowolne litery po nim (np. luty, lutego).
Wynik: 23 wystąpienia.
Zaawansowane przeszukiwanie
Przeszukajmy historię Polski na stronie Wikipedia i znajdźmy akapity, w których jest wzmianka o królu oraz dotyczą XVIII i XIX wieku. Możemy to zrobić na dwa sposoby:
- Określając występowanie dat w danym akapicie przed lub po słowie „król”.
- Korzystając z nowej formuły szukania w przód z wynikiem pozytywnym (positive lookahead).
Pierwszy sposób:
^. *1[7-8][0-9]{2}.*[Kk]ról.*1[7-8][0-9]{2}.*$
Analiza wyrażenia:
- ^ – początek linii.
- .*1[7-8][0-9]{2}.* – szukamy daty (XVIII lub XIX wiek), przed którą mogą być dowolne znaki.
- [Kk]ról – szukamy słowa „król” (pisanego z dużej lub małej litery).
- .* – dowolne znaki po słowie „król”.
- 1[7-8][0-9]{2} – szukamy daty po słowie „król”.
- $ – koniec linii.
Drugi sposób (szukanie w przód z wynikiem pozytywnym):
^(?=.*1[7-8][0-9]{2}).*[Kk]ról.*$
Analiza wyrażenia:
- ^ – początek linii.
- (?=.*1[7-8][0-9]{2}) – szukamy daty (XVIII lub XIX wiek) gdziekolwiek w linii.
- .*[Kk]ról.* – szukamy słowa „król” (pisanego z dużej lub małej litery).
Szukanie w nawiasach
Często w tekście trudno znaleźć, gdzie kończy się nawias. Przykładowy tekst:
„Polska, Rzeczpospolita Polska (RP) – państwo unitarne w Europie Środkowej, położone między Morzem Bałtyckim na północy a Sudetami i Karpatami na południu, w przeważającej części w dorzeczu Wisły i Odry. Od północy Polska graniczy z Rosją (z jej obwodem kaliningradzkim) i Litwą, od wschodu z Białorusią i Ukrainą, od południa ze Słowacją i Czechami, od zachodu z Niemcami. Większość północnej granicy Polski wyznacza wybrzeże Morza Bałtyckiego. Polska Wyłączna Strefa Ekonomiczna na Bałtyku graniczy ze strefami Danii i Szwecji. Granice z Ukrainą, Białorusią i Rosją stanowią równocześnie granicę zewnętrzną Unii Europejskiej i strefy Schengen.”
Wzorzec na wyszukiwanie wyrażeń w nawiasach (działa tylko, gdy nawiasy nie są zagnieżdżone):
Skopiuj kod\(.*?\)
Dzięki operatorowi ? wyrażenie nie jest „zachłanne” i znajdzie zawartość tylko jednego nawiasu.
Podsumowanie
Wyrażenia regularne są potężnym narzędziem do wyszukiwania i manipulowania tekstem. Chociaż na pierwszy rzut oka mogą wydawać się skomplikowane, zrozumienie ich podstawowych zasad pozwala na znaczne zwiększenie efektywności pracy z tekstem. Zachęcam do eksperymentowania i wykorzystywania wyrażeń regularnych w codziennych zadaniach!