Jakie znaki specjalne muszą być poprzedzone znakami regularnymi?

389

Mam dość ciągłego zgadywania, czy powinienem unikać znaków specjalnych, takich jak „ ()[]{}|” itp., Gdy używam wielu implementacji wyrażeń regularnych.

Różni się na przykład w Pythonie, sed, grep, awk, Perl, zmiana nazwy, Apache, find i tak dalej. Czy jest jakiś zestaw reguł, który mówi, kiedy powinienem, a kiedy nie, unikać znaków specjalnych? Czy to zależy od typu wyrażeń regularnych, takich jak PCRE, POSIX lub rozszerzone wyrażenia regularne?

Igor Katson
źródło
4
Dobre biblioteki wyrażeń regularnych mają funkcje takie jak „ escape()”, aby umożliwić stosowanie dowolnych ciągów jako części wyrażeń regularnych.
ivan_pozdeev
2
Możesz używać sprawdzania wyrażeń Regex online, takich jak gskinner.com/RegExr (to nic nie kosztuje). (Wpisz, a następnie umieść kursor myszy nad wyrażeniem regularnym, które wpisałeś)
hexicle 12.12.13
2
Unikaj wszystkich znaków niealfanumerycznych. Kropka.
Salman von Abbas
2
To pytanie zostało dodane do często zadawanych pytań dotyczących wyrażeń regularnych przepełnienia stosu w sekcji „Inne”.
aliteralmind
1
To pytanie zostało dodane do często zadawanych pytań dotyczących wyrażeń regularnych przepełnienia stosu w sekcji „Sekwencje specjalne”.
aliteralmind

Odpowiedzi:

365

To, które postacie musisz, a których nie możesz uciec, zależy od smaku wyrażenia regularnego, z którym pracujesz.

W przypadku PCRE i większości innych tak zwanych smaków zgodnych z Perlem unikaj tych zewnętrznych klas postaci:

.^$*+?()[{\|

i te wewnątrz klas postaci:

^-]\

W przypadku rozszerzonych wyrażeń regularnych POSIX (ERE), unikaj tych zewnętrznych klas znaków (takich samych jak PCRE):

.^$*+?()[{\|

Ucieczka jakichkolwiek innych znaków jest błędem w POSIX ERE.

Wewnątrz klas znaków odwrotny ukośnik to dosłowny znak w wyrażeniach regularnych POSIX. Nie możesz go użyć, aby cokolwiek uciec. Musisz użyć „sprytnego umiejscowienia”, jeśli chcesz uwzględnić metaznaki klasy znaków jako literały. Umieść ^ gdziekolwiek oprócz początku,] na początku i - na początku lub na końcu klasy znaków, aby dosłownie je dopasować, np .:

[]^-]

W POSIX-owych podstawowych wyrażeniach regularnych (BRE) są to metaznaki, które musisz uciec, aby ukryć ich znaczenie:

.^$*[\

Unikanie nawiasów i nawiasów klamrowych w BRE daje im specjalne znaczenie, jakie mają ich nieskalowane wersje w ERE. Niektóre implementacje (np. GNU) również nadają specjalne znaczenie innym znakom podczas ucieczki, takim jak \? i +. Ucieczka od znaku innego niż. ^ $ * () {} Jest zwykle błędem w BRE.

W klasach postaci BRE mają tę samą zasadę, co ERE.

Jeśli wszystko to powoduje, że kręci Ci się w głowie, weź kopię RegexBuddy . Na karcie Utwórz kliknij opcję Wstaw token, a następnie Literał. RegexBuddy doda ucieczki w razie potrzeby.

Jan Goyvaerts
źródło
1
Wydaje mi się, że zapomniałeś znaku „/”, który również musi być zabezpieczony przed klasą.
jackthehipster
11
/nie jest metaznakiem w żadnym ze smaków wyrażeń regularnych, o których wspomniałem, więc składnia wyrażeń regularnych nie wymaga zmiany znaczenia. Gdy wyrażenie regularne jest cytowany jako dosłowny w języku programowania, a następnie ciąg lub regex formatowania reguł tego języka mogą wymagać /lub "czy 'należy uciec, a może nawet wymagać `\` być podwójnie uciekł.
Jan Goyvaerts
2
co z okrężnicą „:”? Czy będzie można go uciec wewnątrz klas postaci, a także na zewnątrz? en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions mówi: „PCRE ma spójne reguły ucieczki: każdy znak
niealfanumeryczny
4
MOŻNA uciec, to nie to samo, co POWINIEN być ucieczką. Składnia PCRE nigdy nie wymaga ucieczki od dosłownego dwukropka, więc uniknięcie dosłownych dwukropków tylko utrudnia odczytanie wyrażenia regularnego.
Jan Goyvaerts,
1
Dla ERE innego niż POSIX (tego, którego używam najczęściej, ponieważ jest to zaimplementowane przez Tcl) ucieczka przed innymi rzeczami nie generuje błędów.
slebetman
61

Nowoczesne smaki RegEx (PCRE)

Obejmuje C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Real Studio, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo, XRegExp.
Kompatybilność z PCRE może się różnić

    Gdziekolwiek: . ^ $ * + - ? ( ) [ ] { } \ |


Starsze RegEx Flavours (BRE / ERE)

Obejmuje awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
Obsługa PCRE może być włączona w późniejszych wersjach lub przy użyciu rozszerzeń

ERE / awk / egrep / emacs

    Poza klasą postaci: . ^ $ * + ? ( ) [ { } \ |
    Wewnątrz klasy postaci:^ - [ ]

BRE / ed / grep / sed

    Poza klasą znaków: . ^ $ * [ \
    Wewnątrz klasy znaków: ^ - [ ]
    W przypadku literałów, nie uciekaj: + ? ( ) { } |
    Aby uzyskać standardowe zachowanie wyrażenia regularnego, należy:\+ \? \( \) \{ \} \|


Notatki

  • Jeśli nie masz pewności co do konkretnej postaci, możesz uciec jak \xFF
  • Znaki alfanumeryczne nie mogą być poprzedzane odwrotnym ukośnikiem
  • Symbole dowolne można uciec za pomocą odwrotnego ukośnika w PCRE, ale nie BRE / ERE (należy je zamykać tylko wtedy, gdy jest to wymagane). Dla PCRE] - potrzebuję tylko ucieczki w obrębie klasy postaci, ale dla uproszczenia trzymałem je na jednej liście
  • Cytowane ciągi wyrażeń muszą także mieć znaki ucieczki otaczających znaków cudzysłowu i często z podwójnymi ukośnikami podwójnymi (jak w "(\")(/)(\\.)"porównaniu do/(")(\/)(\.)/ w JavaScript)
  • Oprócz znaków ucieczki różne implementacje wyrażeń regularnych mogą obsługiwać różne modyfikatory, klasy znaków, kotwice, kwantyfikatory i inne funkcje. Aby uzyskać więcej informacji, sprawdź regular-expressions.info lub użyj regex101.com, aby przetestować swoje wyrażenia na żywo
Beejor
źródło
1
Istnieje wiele błędów w swojej odpowiedzi, włączając, lecz nie ograniczając się do: Żaden ze swoich „nowoczesnych” smakach wymagają -lub ]być ocalałem klas postaci zewnętrznych. POSIX (BRE / ERE) nie ma znaku ucieczki w klasach postaci. Smak regex w RTL Delphi jest oparty na PCRE. Python, Ruby i XML mają swoje własne smaki, które są bliższe PCRE niż POSIX-owi.
Jan Goyvaerts
1
@JanGoyvaerts Dzięki za korektę. Wspomniane smaki są rzeczywiście bliższe PCRE. Jeśli chodzi o ucieczki, trzymałem je w ten sposób dla uproszczenia; łatwiej jest pamiętać tylko o ucieczce wszędzie niż kilka wyjątków. Zaawansowani użytkownicy będą wiedzieć, co jest grane, jeśli chcą uniknąć kilku odwrotnych ukośników. W każdym razie zaktualizowałem swoją odpowiedź o kilka wyjaśnień, które, mam nadzieję, odnoszą się do niektórych z tych rzeczy.
Beejor
22

Niestety tak naprawdę nie ma zestawu kodów ucieczki, ponieważ różni się w zależności od używanego języka.

Jednak utrzymywanie strony takiej jak Strona narzędzi do wyrażeń regularnych lub ta karta z wyrażeniami regularnymi może pomóc w szybkim odfiltrowaniu.

Dillie-O
źródło
1
Ściągawka Dodbytes jest bardzo uproszczona i zawiera rażące błędy. Na przykład mówi \<i \>jest granicami słów, co jest prawdą tylko (AFAIK) w bibliotece wyrażeń regularnych Boost. Ale gdzie indziej jest napisane <i >są metaznakami i muszą być uciekane (do \<i \>), aby dosłownie je dopasować, co nie jest prawdą w żadnym smaku
Alan Moore
5

Niestety znaczenie rzeczy takich jak (i ​​\ (są zamieniane między wyrażeniami regularnymi w stylu Emacsa a większością innych stylów. Więc jeśli spróbujesz uciec od nich, możesz robić coś przeciwnego do tego, czego chcesz.

Więc naprawdę musisz wiedzieć, jaki styl próbujesz zacytować.

Darron
źródło
5

POSIX rozpoznaje wiele odmian wyrażeń regularnych - podstawowe wyrażenia regularne (BRE) i rozszerzone wyrażenia regularne (ERE). Nawet wtedy pojawiają się dziwactwa z powodu historycznych implementacji narzędzi znormalizowanych przez POSIX.

Nie ma prostej zasady określającej, kiedy użyć notacji, a nawet jakiej notacji używa dane polecenie.

Sprawdź książkę Mastering Regular Expressions Jeffa Friedla .

Jonathan Leffler
źródło
4

Naprawdę nie ma. istnieje około pół zyliona różnych składni wyrażeń regularnych; wydają się sprowadzać do Perla, EMACS / GNU i AT&T w ogóle, ale ja też zawsze jestem zaskoczony.

Charlie Martin
źródło
4

Czasami proste ucieczka nie jest możliwa w przypadku postaci, które wymieniłeś. Na przykład użycie ukośnika odwrotnego do nawiasu klamrowego nie będzie działać po lewej stronie łańcucha podstawienia w sed, a mianowicie

sed -e 's/foo\(bar/something_else/'

Zamiast tego używam prostej definicji klasy znaków, więc powyższe wyrażenie staje się

sed -e 's/foo[(]bar/something_else/'

które znajduję działa dla większości implementacji wyrażeń regularnych.

Klasy znaków BTW są dość waniliowymi komponentami regularnymi, więc zwykle działają w większości sytuacji, w których potrzebujesz znaków ucieczkowych w wyrażeniach regularnych.

Edytować: Po komentarzu poniżej, pomyślałem, że wspomnę o tym, że musisz również wziąć pod uwagę różnicę między automatami stanu skończonego a automatami stanu nieskończonego, patrząc na zachowanie oceny wyrażenia regularnego.

Możesz zajrzeć do „książki z błyszczącą kulą”, znanej również jako Effective Perl ( zdezynfekowany link do Amazon) ), a konkretnie do rozdziału o wyrażeniach regularnych, aby poczuć różnicę w typach oceny silnika wyrażenia regularnego.

Nie cały świat jest PCRE!

Zresztą wyrażenia regularne są tak niezgrabne w porównaniu do SNOBOL ! Teraz , że był ciekawy kurs programowania! Wraz z tą na Simuli .

Ach, radość z nauki w UNSW pod koniec lat 70-tych! (-:

Rob Wells
źródło
„sed” to polecenie, dla którego zwykły „(„ nie jest wyjątkowy, ale „\ (” jest wyjątkowy; przeciwnie, PCRE odwraca sens, więc ”(„ jest specjalny, ale „\ (” nie jest. To jest dokładnie to, co OP pyta o:
Jonathan Leffler
sed to narzędzie * nix, które wykorzystuje jeden z najbardziej prymitywnych zestawów wyrażeń regularnych. PCRE nie wchodzi w opisaną przeze mnie sytuację, ponieważ wiąże się z inną klasą (nie) automatów skończonych w sposobie, w jaki ocenia wyrażenia regularne. Myślę, że moja sugestia dotycząca minimalnego zestawu składni wyrażeń regularnych nadal obowiązuje.
Rob Wells,
1
W systemie zgodnym z POSIX sed używa POSIX BRE, co omówię w mojej odpowiedzi. Wersja GNU na nowoczesnym systemie Linux używa POSIX BRE z kilkoma rozszerzeniami.
Jan Goyvaerts
2

W przypadku PHP „zawsze można bezpiecznie poprzedzać znak niealfanumeryczny znakiem„ \ ”, aby określić, że oznacza on siebie”. - http://php.net/manual/en/regexp.reference.escape.php .

Z wyjątkiem jeśli jest to „lub”.: /

Aby uniknąć zmiennych wzorca wyrażeń regularnych (lub zmiennych częściowych) w PHP, użyj preg_quote ()

zylstra
źródło
2

Aby dokładnie wiedzieć, kiedy i co uciec bez prób, konieczne jest dokładne zrozumienie łańcucha kontekstów, przez które przechodzi ciąg. Określisz ciąg od najdalszej strony do jego końcowego miejsca docelowego, którym jest pamięć obsługiwana przez kod parsujący wyrażenia regularnego.

Pamiętaj, jak przetwarzany jest ciąg znaków w pamięci: jeśli może to być zwykły ciąg znaków w kodzie lub ciąg znaków wprowadzony do wiersza poleceń, ale może to być interaktywny wiersz poleceń lub wiersz poleceń podany w pliku skryptu powłoki lub wewnątrz zmiennej w pamięci wymienionej w kodzie lub argumentu (ciągu znaków) w wyniku dalszej oceny lub ciągu zawierającego kod generowany dynamicznie przy użyciu dowolnego rodzaju enkapsulacji ...

Każdemu z tych kontekstów przypisano niektóre znaki o specjalnej funkcjonalności.

Jeśli chcesz przekazać znak dosłownie bez użycia jego specjalnej funkcji (lokalnej dla kontekstu), to jest to przypadek, w którym musisz go uciec, dla następnego kontekstu ... który może wymagać kilku innych znaków zmiany znaczenia, które mogą dodatkowo wymagać uciekł w poprzednich kontekstach. Ponadto mogą istnieć rzeczy takie jak kodowanie znaków (najbardziej podstępny jest utf-8, ponieważ wygląda jak ASCII dla zwykłych znaków, ale może być opcjonalnie interpretowany nawet przez terminal w zależności od jego ustawień, aby mógł zachowywać się inaczej, niż atrybut kodowania HTML / XML, konieczne jest dokładne zrozumienie procesu.

Np. Wyrażenie regularne w linii poleceń zaczynające się od perl -npe, musi zostać przesłane do zestawu exec wywołań systemowych łączących się jako potok obsługi plików, każde z tych wywołań systemowych exec ma tylko listę argumentów oddzielonych spacjami (bez znaków zmiany znaczenia), i ewentualnie potoki (|) i przekierowanie (> N> N> i M), nawiasy, interaktywna rozbudowa *i? ,$(())... (wszystkie są znakami specjalnymi używanymi przez * sh, które mogą wydawać się zakłócać charakter wyrażenia regularnego w następnym kontekście, ale są one oceniane w kolejności: przed wierszem poleceń. Wiersz poleceń jest odczytywany przez program jako bash / sh / csh / tcsh / zsh, zasadniczo wewnątrz podwójnego cudzysłowu lub pojedynczego cudzysłowu ucieczka jest prostsza, ale nie jest konieczne cytowanie ciągu w wierszu poleceń, ponieważ w większości miejsca należy poprzedzić ukośnikiem odwrotnym, a cytat to nie jest konieczne pozostawienie dostępnej funkcji rozwijania dla znaków * i?, ale parsowanie odbywa się w innym kontekście niż w cudzysłowie. Następnie, gdy linia poleceń jest oceniana, wyrażenie regularne uzyskane w pamięci (nie tak jak napisano w linii poleceń) jest traktowane tak samo jak byłby w pliku źródłowym. Dla wyrażenia regularnego istnieje kontekst zestawu znaków w nawiasach kwadratowych [],wyrażenie regularne perl może być cytowane przez duży zestaw znaków niealfanumerycznych (np. m // lub m: / better / for / path: ...).

Masz inne szczegóły na temat znaków w innej odpowiedzi, które są bardzo specyficzne dla końcowego kontekstu wyrażenia regularnego. Jak już wspomniałem, wspomniałeś, że podczas prób odnajdujesz ucieczkę wyrażenia regularnego, prawdopodobnie dlatego, że inny kontekst ma inny zestaw znaków, który mylił twoją pamięć prób (często odwrotny ukośnik to znak używany w tym innym kontekście do ucieczki od literalnego znaku zamiast jego funkcji ).

Marco Munari
źródło
0

W przypadku Ionic (Typescript) musisz podwoić ukośnik, aby przeskalować znaki. Na przykład (w celu dopasowania niektórych znaków specjalnych):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Zwróć uwagę na te ] [ - _ . /postacie. Muszą być podwójnie cięte. Jeśli tego nie zrobisz, w kodzie wystąpi błąd typu.

Alejandro del Río
źródło