Wyrażenia regularne są potężnym narzędziem w arsenale programisty, ale - zdarzają się przypadki, gdy nie są najlepszym wyborem, a nawet wręcz szkodliwe.
Prostym przykładem # 1 jest parsowanie HTML za pomocą regexp - znanej drogi do licznych błędów. Prawdopodobnie wiąże się to również z parsowaniem w ogóle.
Ale czy istnieją inne wyraźne obszary, w których nie można przejść do wyrażeń regularnych?
ps: „ Pytanie, które zadajesz, wydaje się subiektywne i prawdopodobnie zostanie zamknięte. ” - dlatego chcę podkreślić, że interesują mnie przykłady, w których wiadomo, że użycie wyrażeń regularnych powoduje problemy.
Odpowiedzi:
Nie używaj wyrażeń regularnych:
Nie ogranicza się to do HTML . Prostego prawidłowego kodu XML nie można rozsądnie przeanalizować za pomocą wyrażenia regularnego, nawet jeśli znasz schemat i wiesz, że nigdy się nie zmieni.
Nie próbuj na przykład analizować kodu źródłowego C # . Zamiast tego parsuj, aby uzyskać znaczącą strukturę drzewa lub tokeny.
Co jeśli musisz szukać litery, zarówno małej, jak i dużej? Jeśli kochasz wyrażenia regularne, będziesz ich używać. Ale czy nie jest łatwiej / szybciej / czytelniej korzystać z dwóch wyszukiwań, jeden po drugim? W większości języków są szanse, że osiągniesz lepszą wydajność i zwiększysz czytelność kodu.
Na przykład przykładowy kod w odpowiedzi Ingo jest dobrym przykładem, gdy nie wolno używać wyrażeń regularnych. Wyszukaj
foo
, a następniebar
.Dobrym przykładem jest filtr nieprzyzwoitości. Nie tylko ogólnie jest to zły pomysł , ale możesz mieć ochotę zrobić to za pomocą wyrażeń regularnych, a zrobisz to źle. Istnieje wiele sposobów, w jakie człowiek może napisać słowo, liczbę, zdanie i będzie zrozumiany przez innego człowieka, ale nie przez zwykłe wyrażenie. Dlatego zamiast chwytać się prawdziwej nieprzyzwoitości, wyrażenie regularne poświęci jej czas na zranienie innych użytkowników.
Na przykład nie sprawdzaj poprawności adresu e-mail za pomocą wyrażenia regularnego. W większości przypadków zrobisz to źle. W rzadkich przypadkach zrobisz to dobrze i skończysz z kodowaniem horroru o długości 6 343 znaków .
Bez odpowiednich narzędzi popełnisz błędy. I zauważysz je w ostatniej chwili, a może nigdy. Jeśli nie zależy ci na czystym kodzie, napiszesz dwadzieścia wierszy bez komentarzy, spacji i znaków nowej linii.
Poważnie, jeśli wezmę twój kod i będę musiał go przejrzeć lub zmodyfikować, nie chcę spędzić tygodnia próbując zrozumieć ciąg dwudziesto-liniowy wielu symboli.
źródło
(?(DEFINE))
zapewnieniach;) Możesz pisać bardzo czyste wyrażenia regularne za pomocą tych, a właściwie kiedy będziesz używać tych, napiszesz gramatyki, które są bardzo podobny do tego, co napiszesz w yacc lub podobnym;)"<a href='foo'>stuff</a>"
. Współczesne wyrażenia regularne nie mają z tym problemu.Najważniejsze: kiedy przetwarzany język nie jest zwykłym językiem .
HTML nie jest zwykłym językiem, a przetwarzanie go za pomocą wyrażeń regularnych nie jest możliwe (nie tylko trudne lub droga do błędnego kodu).
źródło
Podczas przepływu stosów często ludzie pytają o wyrażenia regularne, które sprawdzą, czy dany ciąg nie zawiera tego czy tamtego. To jest, IMHO, odwrócenie celu wyrażenia regularnego. Nawet jeśli istnieje rozwiązanie (wykorzystujące negatywne spojrzenie za twierdzeniami lub takimi rzeczami), często znacznie lepiej jest użyć wyrażenia regularnego dla tego, co zostało stworzone i obsłużyć ujemny przypadek za pomocą logiki programu.
Przykład:
źródło
Dwa przypadki:
Gdy jest łatwiejszy sposób
Większość języków udostępnia prostą funkcję, taką jak INSTR, w celu ustalenia, czy jeden ciąg znaków jest podzbiorem drugiego. Jeśli to właśnie chcesz zrobić, skorzystaj z prostszej funkcji. Nie pisz własnego wyrażenia regularnego.
Jeśli dostępna jest biblioteka do wykonywania złożonych operacji na łańcuchach, użyj jej zamiast pisać własne wyrażenie regularne.
Gdy wyrażenia regularne nie są wystarczająco potężne
źródło
Wyrażenia regularne nie mogą zidentyfikować struktur rekurencyjnych . To jest podstawowe ograniczenie.
Weźmy JSON - jest to dość prosty format, ale ponieważ obiekt może zawierać inne obiekty jako wartości składowe (dowolnie głębokie), składnia jest rekurencyjna i nie może być analizowana przez wyrażenie regularne. Z drugiej strony CSV może być analizowany przez wyrażenia regularne, ponieważ nie zawiera żadnych struktur rekurencyjnych.
Krótko mówiąc, wyrażenia regularne nie pozwalają wzorowi odnosić się do siebie. Nie możesz powiedzieć: w tym momencie składni ponownie dopasuj cały wzorzec. Innymi słowy, wyrażenia regularne pasują tylko liniowo, nie zawiera stosu, który pozwoliłby mu śledzić, jak głęboko jest to zagnieżdżony wzór.
Pamiętaj, że nie ma to nic wspólnego z tym, jak skomplikowany lub skomplikowany jest format. Wyrażenia S są naprawdę bardzo proste, ale nie można ich analizować za pomocą wyrażenia regularnego. Z drugiej strony CSS2 jest dość złożonym językiem, ale nie zawiera struktur rekurencyjnych i dlatego można go parsować za pomocą wyrażenia regularnego. (Chociaż nie jest to prawdą w przypadku CSS3 ze względu na wyrażenia CSS, które mają składnię rekurencyjną).
Nie dzieje się tak dlatego, że jest brzydki, skomplikowany lub podatny na analizowanie kodu HTML przy użyciu tylko wyrażeń regularnych. Jest to po prostu niemożliwe .
Jeśli musisz przeanalizować format zawierający struktury rekurencyjne, musisz przynajmniej uzupełnić użycie wyrażeń regularnych stosem, aby śledzić poziom struktur rekurencyjnych. Tak zazwyczaj działa parser. Wyrażenia regularne służą do rozpoznawania części „liniowych”, a niestandardowy kod poza wyrażeniem regularnym służy do śledzenia zagnieżdżonych struktur.
Zwykle taka analiza jest podzielona na osobne fazy. Tokenizacja to pierwsza faza, w której wyrażenia regularne są używane do podziału danych wejściowych na sekwencję „tokenów”, takich jak słowa, znaki interpunkcyjne, nawiasy kwadratowe itp. Analiza jest kolejną fazą, w której tokeny te są przetwarzane w strukturę hierarchiczną, drzewo składniowe.
Kiedy więc usłyszysz, że HTML lub C # nie mogą być analizowane za pomocą wyrażeń regularnych, pamiętaj, że wyrażenia regularne nadal są kluczową częścią parserów. Po prostu nie można parsować takiego języka przy użyciu tylko wyrażeń regularnych i kodu pomocniczego.
źródło