W Perl analiza leksykalna (lexing) i parsowanie tekstów często wykorzystywane są do przetwarzania złożonych szablonów tekstowych. Wiele zadań (np. analiza zagnieżdżonych nawiasów, cudzysłowów, zapytań SQL) nie daje się rozwiązać prostymi wyrażeniami regularnymi z powodu ich liniowej natury. W takich przypadkach używa się modułów, które implementują podstawy parsowania — na przykład Text::Balanced.
Text::Balanced jest przeznaczony do wydobywania zrównoważonych nawiasów, par cudzysłowów i innych zagnieżdżonych struktur. Działa tam, gdzie wyrażenia regularne są bezsilne (np. parsowanie zagnieżdżonych konstrukcji { ... { ... } ... }). Wśród alternatyw są moduły Parse::RecDescent, własny kod oparty na stosie i rekursji, a także zewnętrzne parsery.
Przykład użycia Text::Balanced i porównania z regexp:
use Text::Balanced 'extract_bracketed'; my $data = 'foo({bar(baz)},qux)'; my ($extracted, $remainder) = extract_bracketed($data, '()'); print $extracted; # Wyświetli: ({bar(baz)},qux)
Wyrażenie regularne nie będzie w stanie poprawnie przeanalizować zagnieżdżonych nawiasów:
$data =~ /(\(.*\))/; # uchwyci jedynie pierwszy i ostatni nawias, ignorując zagnieżdżenie
Czy można przy użyciu zwykłych wyrażeń regularnych Perl poprawnie wydobyć zrównoważone nawiasy w ciągach o dowolnym poziomie zagnieżdżenia?
Odpowiedź: Nie, wyrażenia regularne Perl nie potrafią pracować z rekurencyjnymi szablonami (z wyjątkiem PCRE, ale nie standardowego Perla). W takim przypadku należy użyć parsera (Text::Balanced, parser na stosie, Parse::RecDescent). Próba rozwiązania problemu za pomocą wyrażenia regularnego doprowadzi do błędów w przypadku zagnieżdżonej składni.
Przykład:
# NIE zadziała dla foo({bar(baz)},qux) my ($br) = $data =~ /(\(.*\))/;
Historia
W projekcie były próby parsowania JSON ręcznie za pomocą wyrażeń regularnych. Programista liczył, że wyrażenie
(\{.*\})znajdzie odpowiedni fragment, ale na rzeczywistych danych z zagnieżdżonymi obiektami parser wybrał niewłaściwą granicę, co doprowadziło do utraty danych i błędów w przetwarzaniu parametrów wejściowych.
Historia
W logach XML zdarzeń potrzebne było wyodrębnienie zawartości tagu z potencjalnie zagnieżdżonymi tagami. Niedostateczne zrozumienie zasad rekursji w leksykalizacji doprowadziło do błędnej analizy zdarzeń i ignorowania zagnieżdżonych elementów — część informacji ginęła.
Historia
Błąd podczas parsowania zapytania SQL przez skrypt migracyjny: wyjątkowe przypadki, takie jak podzapytania w nawiasach, nie udało się poprawnie przeanalizować. Wyrażenia regularne "łamały się" już na poziomie prostych zagnieżdżonych ciągów, w rezultacie czego utworzono niepoprawne zapytania SQL.