Dlaczego moje wyrażenie regularne działa w X, ale nie w Y?


76

Napisałem wyrażenie regularne, które działa dobrze w pewnym programie (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit,…). Ale kiedy używam go w innym programie (lub w innym wariancie unixowym), przestaje on pasować. Dlaczego?

Odpowiedzi:


102

Niestety z przyczyn historycznych różne narzędzia mają nieco inną składnię wyrażeń regularnych, a czasem niektóre implementacje mają rozszerzenia, które nie są obsługiwane przez inne narzędzia. Chociaż istnieje wspólna płaszczyzna, wydaje się, że każdy pisarz narzędzi dokonał różnych wyborów.

W konsekwencji, jeśli masz wyrażenie regularne, które działa w jednym narzędziu, może być konieczne zmodyfikowanie go, aby działało w innym narzędziu. Główne różnice między popularnymi narzędziami to:

  • czy operatorzy +?|(){}wymagają odwrotnego ukośnika;
  • jakie rozszerzenia są obsługiwane poza podstawami .[]*^$i zwykle+?|()

W tej odpowiedzi wymieniam główne standardy . Szczegółowe informacje można znaleźć w dokumentacji używanych narzędzi.

Porównanie aparatów wyrażeń regularnych w Wikipedii zawiera tabelę zawierającą funkcje obsługiwane przez popularne implementacje.

Podstawowe wyrażenia regularne (BRE)

Podstawowe wyrażenia regularne są kodowane przez standard POSIX . Jest używany przez składnia grep, sedi vi. Ta składnia zapewnia następujące funkcje:

  • ^i $dopasuj tylko na początku i na końcu linii.
  • . dopasowuje dowolny znak (lub dowolny znak oprócz nowej linii).
  • […]dopasowuje dowolny znak wymieniony w nawiasach (zestaw znaków). Jeśli pierwszym znakiem po nawiasie otwierającym jest a ^, znaki, które nie są wymienione, są dopasowywane. Aby dołączyć a ], umieść go natychmiast po otwarciu [(lub po, [^jeśli jest to zestaw ujemny). Jeśli -jest między dwoma znakami, oznacza zakres; aby dołączyć literał -, umieść go tam, gdzie nie można go przeanalizować jako zakresu.
  • Odwrotny ukośnik przed dowolnym znakiem ^$.*\[cudzysłowu.
  • * dopasowuje poprzedni znak lub podwyrażenie 0, 1 lub więcej razy.
  • \(…\)jest grupą składniową do użytku z *operatorem lub odniesieniami wstecznymi i \DIGITzamiennikami.
  • Odwołania wsteczne \1, \2… dopasuj dokładnie tekst pasujący do odpowiedniej grupy, np. Pasuje, ale nie \(fo*\)\(ba*\)\1pasuje . Nie ma standardowego sposobu na odniesienie się do 10. grupy i poza nią (standardowe znaczenie to pierwsza grupa, po której następuje a ).foobaafoofoobaafo\100

Następujące funkcje są również standardowe, ale brakuje ich w niektórych ograniczonych implementacjach:

  • \{m,n\}dopasowuje poprzedzający znak lub podwyrażenie między m do n razy; n lub m można pominąć i oznacza dokładnie m .\{m\}
  • W nawiasach można stosować klasy znaków , na przykład [[:alpha:]]pasujące do dowolnej litery. Nowoczesne implementacje wyrażeń w nawiasach ) obejmują także zestawianie elementów typu [.ll.]i klasy równoważności typu [=a=].

Poniżej przedstawiono popularne rozszerzenia (szczególnie w narzędziach GNU), ale nie we wszystkich implementacjach. Sprawdź instrukcję obsługi używanego narzędzia.

  • \|na przemian: foo\|barmecze foolub bar.
  • \?(skrót dla \{0,1\}) i \+(skrót dla \{1,\}) odpowiadają poprzedzającemu znakowi lub podwyrażeniu odpowiednio co najwyżej 1 raz lub co najmniej 1 raz.
  • \ndopasowuje nowy wiersz, \tpasuje do karty itp.
  • \wdopasowuje dowolny składnik słowa (skrót, [_[:alnum:]]ale ze zmiennością, jeśli chodzi o lokalizację) i \Wpasuje do każdego znaku, który nie jest składnikiem słowa.
  • \<i \>dopasuj pusty ciąg tylko odpowiednio na początku lub na końcu słowa; \bpasuje albo i \Bpasuje tam, gdzie \bnie.

Pamiętaj, że narzędzia bez \|operatora nie mają pełnej mocy wyrażeń regularnych. Odwołania wsteczne pozwalają na kilka dodatkowych rzeczy, których nie można zrobić za pomocą wyrażeń regularnych w sensie matematycznym.

Rozszerzone wyrażenia regularne (ERE)

Rozszerzone wyrażenia regularne są kodowane przez standard POSIX . Ich główną zaletą w stosunku do BRE jest regularność: wszystkie standardowe operatory są czystymi znakami interpunkcyjnymi, odwrotny ukośnik przed znakiem interpunkcyjnym zawsze go cytuje. Jest to składnia używana przez awk, grep -Elub egrep, GNU sed -ri operator bash=~ . Ta składnia zapewnia następujące funkcje:

  • ^i $dopasuj tylko na początku i na końcu linii.
  • . dopasowuje dowolny znak (lub dowolny znak oprócz nowej linii).
  • […]dopasowuje dowolny znak wymieniony w nawiasach (zestaw znaków). Uzupełnienie początkowym ^i zakresami działa jak w BRE (patrz wyżej). Klasy postaci mogą być używane, ale brakuje ich w kilku implementacjach. Nowoczesne implementacje obsługują również klasy równoważności i zestawianie elementów. Ukośnik odwrotny w nawiasach cytuje następny znak w niektórych, ale nie we wszystkich implementacjach; Służy \\do oznaczenia odwrotnego ukośnika dla przenośności.
  • (…)jest grupą składniową do użytku z *lub \DIGITzamienników.
  • |na przemian: foo|barmecze foolub bar.
  • *, +i ?dopasowuje poprzedni znak lub podwyrażenie wiele razy: 0 lub więcej dla *, 1 lub więcej dla +, 0 lub 1 dla ?.
  • Odwrotny ukośnik cytuje następny znak, jeśli nie jest on alfanumeryczny.
  • {m,n}znak poprzedzający lub podwyrażenie pomiędzy m i n razy (brakuje niektórych implementacjach); n lub m można pominąć i oznacza dokładnie m .{m}
  • Niektóre typowe rozszerzenia jak w BRE: odnośniki zwrotne (szczególnie nieobecne w awk, z wyjątkiem implementacji busybox, w której można użyć ); znaki specjalne , itp .; granice słów oraz składniki słów i …\DIGIT$0 ~ "(...)\\1"\n\t\b\B\b\B

PCRE (wyrażenia regularne zgodne z Perlem)

PCRE to rozszerzenia ERE, pierwotnie wprowadzone przez Perla i przyjęte przez GNU grep -Poraz wiele nowoczesnych narzędzi i języków programowania , zwykle za pośrednictwem biblioteki PCRE . Zobacz dokumentację Perla, aby uzyskać ładne formatowanie z przykładami. Nie wszystkie funkcje najnowszej wersji Perla są obsługiwane przez PCRE (np. Wykonywanie kodu w Perlu jest obsługiwane tylko w Perlu). Patrz podręcznik PCRE na podsumowanie obsługiwanych funkcji. Główne dodatki do ERE to:

  • (?:…)jest grupą nie przechwytującą: polubienie (…), ale nie ma znaczenia dla odnośników zwrotnych.
  • (?=FOO)BAR(lookahead) pasuje BAR, ale tylko wtedy, gdy istnieje również dopasowanie do FOOrozpoczęcia od tej samej pozycji. Jest to najbardziej przydatne do zakotwiczenia dopasowania bez dołączania następującego tekstu: foo(?=bar)dopasowania, fooale tylko wtedy, gdy następuje po nim bar.
  • (?!FOO)BAR(negatywne spojrzenie w przód) pasuje BAR, ale nie ma również dopasowania dla FOOtej samej pozycji. Na przykład (?!foo)[a-z]+pasuje do każdego małego słowa, które się nie zaczyna foo; [a-z]+(?![0-9)dopasowuje dowolne małe litery, po których nie następuje cyfra (więc w foo123, pasuje, foale nie foo).
  • (?<=FOO)BAR(lookbehind) pasuje BAR, ale tylko jeśli jest to bezpośrednio poprzedzone dopasowaniem dla FOO. FOOmusi mieć znaną długość (nie można używać operatorów powtarzania, takich jak *). Jest to najbardziej przydatne do zakotwiczenia dopasowania bez uwzględnienia poprzedzającego tekstu w dopasowaniu: (?<=^| )foodopasowania, fooale tylko wtedy, gdy poprzedza go spacja lub początek łańcucha.
  • (?<!FOO)BAR(negatywny wygląd) pasuje BAR, ale tylko wtedy, gdy nie jest bezpośrednio poprzedzone dopasowaniem dla FOO. FOOmusi mieć znaną długość (nie można używać operatorów powtarzania, takich jak *). Jest to najbardziej przydatne do zakotwiczenia dopasowania bez uwzględnienia poprzedzającego tekstu w dopasowaniu: (?<![a-z])foodopasowania, fooale tylko wtedy, gdy nie jest poprzedzone małą literą.

Emacs

Składnia Emacsa jest pośrednia między BRE a ERE. Oprócz Emacsa jest to domyślna składnia -regexw GNU find. Emacs oferuje następujących operatorów:

  • ^, $, ., […], *, +, ?Jak w ERE
  • \(…\), \|, \{…\}, Jak w BRE\DIGIT
  • więcej sekwencji liter odwrotnych ; \<i \>dla granic słów; i więcej w najnowszych wersjach Emacsa, które często nie są obsługiwane w innych silnikach ze składnią podobną do Emacsa.

Globusy powłoki

Globusy powłoki (symbole wieloznaczne) wykonują dopasowywanie wzorców ze składnią, która jest całkowicie różna od wyrażeń regularnych i mniej wydajna. Oprócz powłok te symbole wieloznaczne są dostępne z innymi narzędziami, takimi jak find -namefiltry i rsync. Wzorce POSIX obejmują następujące funkcje:

  • ? pasuje do dowolnego pojedynczego znaku.
  • […]to zestaw znaków jak w typowych składniach wyrażeń regularnych. Niektóre powłoki nie obsługują klas znaków. Niektóre pociski wymagają !zamiast ^negowania zestawu.
  • *dopasowuje dowolną sekwencję znaków (często z wyjątkiem /dopasowywania ścieżek plików; jeśli /jest wykluczony *, to **czasami obejmuje /, ale sprawdź dokumentację narzędzia).
  • Odwrotny ukośnik cytuje następny znak.

Ksh oferuje dodatkowe funkcje, które nadają wzorowi pełną moc wyrażeń regularnych. Te funkcje są również dostępne w wersji bash po uruchomieniu shopt -s extglob. Zsh ma inną składnię, ale może również obsługiwać składnię ksh później setopt ksh_glob.


Inne bogate RE, o których warto wspomnieć, to vimlibast (jak i in ksh93) AT&T .
Stéphane Chazelas

@ StéphaneChazelas Oprócz vima, jaki program używa wyrażeń regularnych vim? Który program oprócz ksh używa libast?
Gilles

cały zestaw narzędzi AT & T używa Res AT & T ( grep, tw, expr...). Z wyjątkiem kshtego, że ten zestaw narzędzi rzadko znajduje się poza AT&T.
Stéphane Chazelas

Zgodnie z moim rozumieniem (i Wikipedii) termin „klasa znaków” faktycznie odnosi się do „klasy znaków POSIX”… jednak regex(7)zgadza się z tobą i nazywa [these]„wyrażenia w nawiasach” i (w ramach „wyrażeń w nawiasie”) [:these:]„klasy znaków”. Nie jestem pewien, jak najlepiej to rozwiązać.
Adam Katz

Jakkolwiek je nazwiesz, obsługują zakresy. Zdecydowanie warto zauważyć, że -określa on zakres i należy albo uciec, najpierw (po opcjonalnym ^), albo ostatni, jeśli ma być traktowany dosłownie. (Widziałem wiele błędów wynikających np. Z - [A-z]zwróć uwagę na wielkość liter w przypadku - które pasują do znaków o kodach od 65 do 122 i przypadkowo zawierają wszystkie z następujących:. [\]^_`Widziałem również prawidłowe, ale mylące [!-~]dopasowanie wszystkich znaków do wydruku w ANSI , co wolę widzieć jako [\x21-\x7e], co najmniej proste w działaniu, ale mylące w innym wymiarze.)
Adam Katz
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.