Wyrażenia regularne (ang. regular expressions, w skrócie regex)

Wyrażenia regularne (ang. regular expressions, w skrócie regex) to jedno z najpotężniejszych narzędzi w programowaniu, które umożliwia pracę z tekstem na zaawansowanym poziomie. Zastosowanie wyrażeń regularnych jest niezwykle szerokie – od walidacji danych, przez wyszukiwanie i zastępowanie, aż po bardziej złożone operacje na ciągach znaków. Choć dla wielu programistów wyrażenia regularne mogą być nieco trudne do zrozumienia na początku, ich znajomość z pewnością znacząco ułatwia życie w codziennej pracy. W tym artykule przyjrzymy się wyrażeniom regularnym, ich składni oraz zastosowaniom w różnych językach programowania.

Czym są wyrażenia regularne?

Wyrażenia regularne to ciągi znaków, które tworzą wzorce wykorzystywane do dopasowywania, przetwarzania i manipulowania tekstami. Wzorzec wyrażenia regularnego (regex) jest jak instrukcja, która mówi programowi, jakiego rodzaju tekstu szukać. Często jest używane do:

  • Wyszukiwania określonych wzorców w tekście.
  • Zastępowania fragmentów tekstu innymi danymi.
  • Walidacji danych (np. sprawdzanie poprawności adresu e-mail, numeru telefonu, czy numeru karty kredytowej).
  • Podziału tekstu na fragmenty (np. dzielenie ciągu na słowa lub frazy).

Wyrażenia regularne są wspierane przez wiele języków programowania, takich jak Python, JavaScript, Java, PHP, Perl, i wiele innych.

Podstawowe składniki wyrażeń regularnych

Aby w pełni wykorzystać potencjał wyrażeń regularnych, warto poznać kilka kluczowych składników, które je tworzą. Są to m.in.:

1. Znaki literalne

Znaki literalne to zwykłe znaki, które odpowiadają dokładnie temu, co jest napisane. Na przykład:

  • a – pasuje do litery „a” w tekście.
  • 123 – pasuje dokładnie do ciągu znaków „123”.

2. Metaznaki

Metaznaki to specjalne znaki, które mają inne znaczenie niż ich literalne odpowiedniki. Do najważniejszych metaznaków należą:

  • . – pasuje do dowolnego pojedynczego znaku (oprócz znaku nowej linii).
  • ^ – oznacza początek ciągu.
  • $ – oznacza koniec ciągu.
  • [] – zbiór znaków, który pasuje do dowolnego pojedynczego znaku z tego zbioru.
    • Na przykład, [abc] pasuje do „a”, „b” lub „c”.
  • | – operator alternatywy, który pozwala na wybór między dwoma wzorcami. Na przykład abc|def pasuje do „abc” lub „def”.

3. Klasy znaków

Niektóre znaki mają specjalne znaczenie w wyrażeniach regularnych, służąc do dopasowywania szerszych kategorii znaków. Na przykład:

  • \d – pasuje do dowolnej cyfry (od 0 do 9).
  • \D – pasuje do dowolnego znaku, który nie jest cyfrą.
  • \w – pasuje do dowolnego znaku alfanumerycznego (litery, cyfry oraz znak podkreślenia).
  • \W – pasuje do dowolnego znaku, który nie jest alfanumeryczny.
  • \s – pasuje do dowolnego białego znaku (spacje, tabulatory, znaki nowej linii).
  • \S – pasuje do dowolnego znaku, który nie jest białym znakiem.

4. Kwantyfikatory

Kwantyfikatory określają, ile razy dany element wyrażenia regularnego ma wystąpić w tekście. Do najczęściej używanych należą:

  • * – oznacza „zero lub więcej” wystąpień.
  • + – oznacza „jedno lub więcej” wystąpień.
  • ? – oznacza „zero lub jedno” wystąpienie.
  • {n} – oznacza dokładnie „n” wystąpień danego elementu.
  • {n,} – oznacza „co najmniej n” wystąpień.
  • {n,m} – oznacza „od n do m” wystąpień.

5. Grupowanie i przechwytywanie

Grupy pozwalają na grupowanie części wyrażenia regularnego, co umożliwia dopasowanie do bardziej złożonych struktur tekstowych. Można również przechwytywać dopasowane fragmenty i używać ich później.

  • () – służy do tworzenia grup. Na przykład (abc)+ pasuje do jednej lub więcej wystąpień ciągu „abc”.
  • \1, \2, … – odnosi się do przechwyconych grup. Na przykład (\d+)\s+\1 pasuje do liczby, a następnie tego samego numeru po jakiejkolwiek liczbie białych znaków.

6. Znaki specjalne

Niektóre znaki mają specjalne znaczenie w wyrażeniach regularnych i muszą być „ucieczone” za pomocą ukośnika odwrotnego (\), aby były traktowane dosłownie. Na przykład:

  • \. – pasuje do kropki.
  • \\ – pasuje do ukośnika odwrotnego.
  • \[ – pasuje do znaku otwartego nawiasu kwadratowego.
  • \] – pasuje do znaku zamkniętego nawiasu kwadratowego.

Zastosowania wyrażeń regularnych

1. Wyszukiwanie i zamiana tekstu

Jednym z najczęstszych zastosowań wyrażeń regularnych jest wyszukiwanie i zamiana fragmentów tekstu. W wielu językach programowania dostępne są funkcje, które umożliwiają wykorzystanie wyrażeń regularnych w tym celu. Na przykład, w Pythonie:

import re tekst = "To jest przykładowy tekst." wynik = re.sub(r'przykładowy', 'zamieniony', tekst) print(wynik)

Wynik: To jest zamieniony tekst.

2. Walidacja danych

Wyrażenia regularne są powszechnie wykorzystywane do walidacji danych wejściowych, takich jak adresy e-mail, numery telefonów czy numery kart kredytowych. Przykładem może być walidacja adresu e-mail w Pythonie:

import re def waliduj_email(email):     wzorzec = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'     return bool(re.match(wzorzec, email)) print(waliduj_email("test@example.com"))  # True print(waliduj_email("test@com"))  # False

3. Przetwarzanie dużych zbiorów danych

Wyrażenia regularne sprawdzają się także w przetwarzaniu dużych zbiorów danych, szczególnie w przypadku logów, gdzie często trzeba wyciągnąć konkretne informacje, takie jak adresy IP, daty czy statusy. Dzięki użyciu odpowiednich wzorców regex można szybko wyodrębnić pożądane fragmenty tekstu.

4. Parsowanie danych w HTML i XML

Chociaż wyrażenia regularne nie są najlepszym narzędziem do parsowania HTML czy XML (gdzie lepiej sprawdzają się dedykowane biblioteki), to w wielu prostych przypadkach mogą one być wystarczające do wyciągania konkretnych danych z dokumentów HTML lub XML.

Przykłady w różnych językach programowania

Python:

import re pattern = r'hello' text = 'hello world' match = re.search(pattern, text) if match:     print("Znaleziono dopasowanie!")

JavaScript:

const pattern = /hello/; const text = 'hello world'; if (pattern.test(text)) {     console.log('Znaleziono dopasowanie!'); }

Java:

import java.util.regex.*; public class Main {     public static void main(String[] args) {         String pattern = "hello";         String text = "hello world";         Pattern p = Pattern.compile(pattern);         Matcher m = p.matcher(text);         if (m.find()) {             System.out.println("Znaleziono dopasowanie!");         }     } }

Złożoność wyrażeń regularnych

Chociaż wyrażenia regularne są bardzo potężnym narzędziem, ich składnia może być początkowo trudna do opanowania, zwłaszcza dla osób, które nie miały wcześniej do czynienia z wyrażeniami regularnymi. Ważne jest, aby poświęcić czas na naukę i praktykę, aby wykorzystać je w pełni w projektach.