Czym dokładnie jest "raw string regex" i jak można go używać?

Z dokumentacji Pythona na regex , dotyczący znaku '\':

Rozwiązaniem jest użycie surowej notacji ciągów Pythona dla zwykłych wzorców wyrażeń; odwrotne ukośniki nie są obsługiwane w żaden specjalny sposób w literalny ciąg znaków poprzedzony 'r'. Więc r"\n" jest ciągiem dwuznakowym zawiera '\' i 'n', natomiast "\n" jest ciągiem jednoznakowym zawiera nowy wiersz. Zwykle wzory będą wyrażane w Pythonie kod wykorzystujący ten surowy ciąg znaków notacja.

Co to jest ten surowy zapis ciągów? Jeśli używasz formatu RAW string, czy to oznacza, że "*" jest traktowany jako literalny znak, a nie zero-lub-więcej wskaźnik? To oczywiście nie może być prawda, inaczej regex całkowicie straci swoją moc. Ale jeśli jest to surowy ciąg znaków, Jak rozpoznaje znaki nowej linii, Jeśli {[5] } jest dosłownie ukośnikiem odwrotnym i "n"?

Nie nadążam.

Edit for bounty:

Próbuję zrozumieć w jaki sposób surowe wyrażenia regularne pasują do nowych linii, tabulatorów i zestawów znaków, np. \w dla słów lub \d dla cyfr lub wszystkich innych, jeśli surowe wzorce łańcuchów nie rozpoznają ukośników jako czegoś więcej niż zwykłych znaków. Przydałyby mi się dobre przykłady.

Author: Yyttsa, 2012-10-13

5 answers

Odpowiedź Zarkonnena odpowiada na twoje pytanie, ale nie bezpośrednio. Spróbuję być bardziej bezpośredni i zobaczę, czy uda mi się zdobyć nagrodę od Zarkonnena.

Być może łatwiej będzie Ci to zrozumieć, jeśli przestaniesz używać terminów "raw string regex" i "raw string patterns". Terminy te łączą dwa oddzielne pojęcia: reprezentacje określonego ciągu znaków w kodzie źródłowym Pythona i jakie Wyrażenie regularne reprezentuje ten ciąg znaków.

[[16]}w rzeczywistości, to jest pomocne, aby myśleć o są to dwa różne języki programowania, każdy z własną składnią. Język Python posiada kod źródłowy, który między innymi buduje ciągi znaków z określoną zawartością i wywołuje system wyrażeń regularnych. System wyrażeń regularnych ma kod źródłowy, który znajduje się w obiektach łańcuchowych i dopasowuje łańcuchy. Oba języki używają odwrotnego ukośnika jako znaku escape.

Najpierw zrozum, że ciąg znaków jest sekwencją znaków (np. bajtów lub punktów kodu Unicode; rozróżnienie nie ma tu większego znaczenia). Istnieje wiele sposobów reprezentacji ciągu znaków w kodzie źródłowym Pythona. A raw string jest po prostu jedną z tych reprezentacji. Jeśli dwie reprezentacje dają ten sam ciąg znaków, to wytwarzają równoważne zachowanie.

Wyobraź sobie dwuznakowy ciąg znaków, składający się z ukośnika wstecznego, po którym następuje znak n. Jeśli wiesz, że wartość znaku dla odwrotnego ukośnika wynosi 92, a dla n wynosi 110, to to wyrażenie generuje nasz łańcuch znaków:

s = chr(92)+chr(110)
print len(s), s

2 \n

Konwencjonalna notacja Pythona "\n" nie generuje tego ciągu. Zamiast tego generuje jednoznakowy ciąg znaków ze znakiem nowej linii. Python docs 2.4.1. Literały ciągów powiedzmy, " znak ukośnika ( \ ) jest używany do ucieczki znaków, które w przeciwnym razie mają specjalne znaczenie, takie jak nowy wiersz, sam ukośnik lub znak cudzysłowu."

s = "\n"
print len(s), s

1 
 

(zauważ, że nowy wiersz nie jest widoczny w tym przykład, ale jeśli przyjrzysz się uważnie, zobaczysz pustą linię po "1".)

Aby otrzymać nasz dwuznakowy ciąg znaków, musimy użyć innego ukośnika wstecznego , aby uciec specjalne znaczenie oryginalnegoukośnika wstecznego znaku:

s = "\\n"
print len(s), s

2 \n

Co zrobić, jeśli chcesz reprezentować ciągi znaków, które mają wiele odwrotnego ukośnika znaków w nich? Python docs 2.4.1. Literały ciągów Kontynuuj, " literały ciągów mogą być opcjonalnie poprzedzone literą "r" lub "R"; takie ciągi są nazywane surowymi ciągami i używają różnych reguł interpretacji sekwencji specjalnych odwrotnego ukośnika."Oto nasz dwuznakowy ciąg znaków, wykorzystujący reprezentację raw string:

s = r"\n"
print len(s), s

2 \n

Mamy więc trzy różne reprezentacje łańcuchów, wszystkie dające ten sam łańcuch lub sekwencję znaków:

print chr(92)+chr(110) == "\\n" == r"\n"
True
Przejdźmy teraz do wyrażeń regularnych. Python docs, 7.2. re - operacje wyrażeń regularnych mówi: "wyrażenia regularne używają znak odwrotnego ukośnika ( " \ " ), aby wskazać specjalne formy lub aby umożliwić użycie znaków specjalnych bez wywoływania ich specjalnego znaczenia. To koliduje z użyciem Pythona tego samego znaku w tym samym celu w literałach łańcuchowych..."

Jeśli chcesz, aby obiekt wyrażenia regularnego Pythona pasował do znaku nowej linii, potrzebujesz 2-znakowego ciągu znaków, składającego się z znaku odwrotny ukośnik, po którym następuje znak n. Następujące linie kodu wszystkie ustawione prog do obiektu wyrażenia regularnego, który rozpoznaje znak nowej linii:

prog = re.compile(chr(92)+chr(110))
prog = re.compile("\\n")
prog = re.compile(r"\n")

Więc dlaczego " Zwykle wzory będą wyrażane w kodzie Pythona przy użyciu tej surowej notacji łańcuchowej."? Ponieważ wyrażenia regularne są często ciągami statycznymi, które są wygodnie reprezentowane jako literały łańcuchowe. I z różnych dostępnych zapisów ciągów znaków, surowe ciągi znaków są wygodnym wyborem, gdy wyrażenie regularne zawiera odwrotny ukośnik charakter.

Pytania

Q: a co z wyrażeniem re.compile(r"\s\tWord")? A : łatwiej jest to zrozumieć, oddzielając łańcuch znaków od kompilacji wyrażeń regularnych i rozumiejąc je oddzielnie.

s = r"\s\tWord"
prog = re.compile(s)

Ciąg s zawiera osiem znaków: a ukośnik wsteczny , an s , a ukośnik wsteczny , a t , a następnie cztery znaki Word.

Q: co dzieje się z tabulatorem i spacją postacie? A : na poziomie języka Python, string s nie ma tabulatora i spacji . Zaczyna się od czterech znaków: ukośnik wsteczny, s, backslash, t . System wyrażeń regularnych traktuje ten łańcuch jako kod źródłowy w języku wyrażeń regularnych, gdzie oznacza " dopasuj łańcuch składający się ze znaków spacji, znaku tabulacji i czterech znaków Word.

Q: jak dopasować te, jeśli to jest traktowane jako backlash-s i backslash-t? A : może pytanie jest jaśniejsze, jeśli słowa " Ty " i "tamto" są bardziej szczegółowe: jak system wyrażeń regularnych pasuje do wyrażeń backlash-s i backslash-t? Jako "dowolny znak spacji" oraz jako " znaktabulator".

Q: albo co jeśli masz 3-znakowy ciąg odwrotny ukośnik-N-newline? A : w Pythonie język, 3-znakowy łańcuch odwrotnego ukośnika-N-newline może być reprezentowany jako konwencjonalny łańcuch "\\n\n", lub raw plus konwencjonalny łańcuch r"\n" "\n", lub w inny sposób. System wyrażeń regularnych pasuje do 3-znakowego ciągu znaków backslash-n-newline, gdy znajdzie dowolne dwa kolejne znaki newline.

Uwaga: wszystkie przykłady i odniesienia do dokumentów odnoszą się do Pythona 2.7.

Update: włączone wyjaśnienia z odpowiedzi @ Vladislav Zorov I @m.buettner, oraz z odpowiedzi na pytanie @ Aerovistae.

 50
Author: Jim DeLaHunt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-19 20:29:28

Większość z tych pytań ma w sobie wiele słów i być może trudno jest znaleźć odpowiedź na konkretne pytanie.

Jeśli używasz zwykłego ciągu znaków i przekazujesz go w taki sposób, jak "\t" do parsera RegEx, Python przetłumaczy ten literał do bufora z bajtem tabulacji (0x09).

Jeśli używasz surowego ciągu znaków i przekazujesz go w taki sposób, jak r"\t" do parsera RegEx, Python nie robi żadnej interpretacji i tworzy bufor z dwoma bajtami: '\ ' i 't'. (0x5c, 0x74).

Parser RegEx wie, co zrobić z sekwencją '\t ' -- dopasowuje to do tabulacji. Wie również, co zrobić ze znakiem 0x09 -- który również pasuje do karty. W większości przypadków wyniki będą nieodróżnialne.

Kluczem do zrozumienia tego, co się dzieje, jest rozpoznanie, że są tu używane dwa parsery. Pierwszy z nich to Parser Pythona, który tłumaczy Twój ciąg znaków (lub surowy ciąg znaków) na sekwencję bajtów. Na drugi to Parser wyrażeń regularnych Pythona, który konwertuje sekwencję bajtów na skompilowane Wyrażenie regularne.

 9
Author: Geoff Gerrietts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-13 15:00:07

Wydaje się, że zmagasz się z myślą, że wyrażenia regularne nie są częścią Pythona, ale zamiast tego innym językiem programowania z własnym parserem i kompilatorem. Surowe ciągi znaków pomagają uzyskać" kod źródłowy " wyrażenia regularnego bezpiecznie do parsera RegEx, który następnie przydziela znaczenie sekwencjom znaków, takim jak \d, \w, \n, itd...

Problem istnieje, ponieważ Python i wyrażenia regularne używają \ jako znaku escape, co jest, nawiasem mówiąc, zbiegiem okoliczności - istnieją języki z innymi znakami escape znaki (jak" ' n "dla nowej linii, ale nawet tam musisz użyć" \n " w wyrażeniach regularnych). Zaletą jest to, że nie trzeba odróżniać RAW i nie-raw ciągów w tych językach, nie będą one zarówno próbować przekonwertować tekst i rzeźnika go, ponieważ reagują na różne sekwencje specjalne.

 3
Author: Vladislav Zorov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-12 17:58:46

Problem z używaniem zwykłego ciągu do zapisu wyrażeń regularnych zawierających \ polega na tym, że musisz napisać \\ dla każdego \. Tak więc literały ciągu "stuff\\things" i r"stuff\things" tworzą ten sam ciąg. Staje się to szczególnie przydatne, jeśli chcesz napisać Wyrażenie regularne, które pasuje do odwrotnych ukośników.

Używając zwykłych łańcuchów, Wyrażenie regularne pasujące do ciągu \ będzie "\\\\"!

Dlaczego? Ponieważ musimy uciec \ dwa razy: raz dla składni wyrażenia regularnego, i raz dla składni ciągów.

Możesz używać potrójnych cudzysłowów do dodawania nowych linii, jak to:

r'''stuff\
things'''

Zauważ, że zazwyczaj python traktowałby \-newline jako kontynuację linii, ale tak nie jest w surowych ciągach. Należy również zauważyć, że odwrotne ukośniki nadal unikają cudzysłowów w surowych ciągach, ale pozostają same w sobie. Tak więc surowy ciąg znaków r"\"" tworzy ciąg \". Oznacza to, że nie można zakończyć surowego ciągu literalnym z odwrotnym ukośnikiem.

Zobacz leksyka sekcja analiza dokumentacji Pythona aby uzyskać więcej informacji.

 2
Author: Zarkonnen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-02 21:30:35

Odpowiednia sekcja podręcznika Pythona ("string and Bytes literaals") zawiera jasne wyjaśnienie nieprzetworzonych literałów łańcuchowych:

Zarówno literały typu string, jak i bajty mogą być opcjonalnie poprzedzone znakiem litera " r " lub "R"; takie ciągi nazywane są ciągami surowymi i traktują ukośniki jako znaki dosłowne. W rezultacie w literach ciągów, Ucieczki '\U ' i '\u' w surowych łańcuchach nie są traktowane specjalnie. Podano ten Pyton 2.surowe literały unicode x zachowują się inaczej niż Python 3.x ' s the składnia 'ur' NIE JEST OBSŁUGIWANA.

Nowość w wersji 3.3: przedrostek' rb ' surowych liter bajtów został dodany jako synonim "br".

Nowość w wersji 3.3: Wsparcie dla dosłownego dziedziczenia unicode (U 'value') został ponownie wprowadzony w celu uproszczenia obsługi dual Python 2.x i 3.x codebases. Więcej informacji można znaleźć w dokumencie PEP 414.

W potrójnie cytowanych ciągach dozwolone są nieocenzurowane nowe linie i cudzysłowy (i są zachowane), z tą różnicą, że trzy cudzysłowy z rzędu Zakończ łańcuch. ("Quote" to znak używany do otwarcia string, tzn. albo 'albo".)

Jeśli nie występuje przedrostek " r " lub "R", sekwencje escape w łańcuchach są interpretowane według zasad podobnych do stosowanych przez Standard C. rozpoznawane sekwencje escape to:

Sekwencja Ucieczki Znaczenie Notatek

\ Newline Backslash i newline ignorowane
\ Backslash ()
\ 'Single quote (' )
\ "Double quote (" )
\dzwonek ASCII (BEL)
\B ASCII Backspace (BS)
\F ASCII Formfeed (FF)
\N ASCII Linefeed (LF)
\R ASCII Carriage Return (CR)
\T ASCII Horizontal Tab (TAB) \V ASCII Vertical Tab (VT)
\OOO znak o wartości ósemkowej ooo (1,3)
\Xhh znak z wartością hex hh (2,3)

Sekwencje specjalne rozpoznawane tylko w literałach łańcuchowych to:

Sekwencja Escape oznaczająca Notes \n {nazwa} znak o nazwie name w Unicode database (4) \ Uxxxx znak z 16-bitową wartością szesnastkową xxxx (5) \Uxxxxxxx znak z 32-bitową wartością szesnastkową xxxxxxxx (6)

Uwagi:

  1. Podobnie jak w standardzie C, akceptowane są do trzech ósemkowych cyfr.

  2. W Przeciwieństwie Do standardowego C, wymagane są dokładnie dwie cyfry szesnastkowe.

  3. W literale bajtowym znaki specjalne szesnastkowe i ósemkowe oznaczają bajt o podanej wartości. W literalnym łańcuchu znaki te oznaczają Znak Unicode o podanej wartości.

  4. Zmiana w wersji 3.3: Dodano obsługę aliasów nazw [1].

  5. Poszczególne jednostki kodu, które tworzą części pary zastępczej, mogą być kodowane za pomocą tej sekwencji escape. Dokładnie cztery cyfry hex to wymagane.

  6. Każdy znak Unicode może być zakodowany w ten sposób, ale znaki spoza podstawowej płaszczyzny wielojęzycznej (BMP) będą zakodowane za pomocą para zastępcza, jeśli Python jest kompilowany do użycia 16-bitowych jednostek kodu ( domyślnie). Dokładnie osiem hex wymagane są cyfry.

W Przeciwieństwie Do standardowego C, wszystkie nierozpoznane sekwencje escape pozostają w ciąg znaków bez zmian, tzn. w łańcuchu pozostaje odwrotny ukośnik. (To zachowanie jest użyteczne podczas debugowania: jeśli sekwencja escape jest błędnie wpisana, wynik końcowy jest łatwiej rozpoznawany jako uszkodzony.) Jest również należy pamiętać, że sekwencje specjalne rozpoznawane są tylko w łańcuchu znaków literały należą do kategorii nierozpoznanych ucieczek dla bajtów literały.

Nawet w nieprzetworzonym łańcuchu, cudzysłowy mogą być usuwane z odwrotnym ukośnikiem, ale odwrotny ukośnik pozostaje w łańcuchu; na przykład R"\" " jest poprawnym ciąg znaków składający się z dwóch znaków: odwrotnego ukośnika i podwójnego quote; r " \ " nie jest poprawnym ciągiem znaków (nawet surowy ciąg znaków nie może kończy się nieparzystą liczbą ukośników wstecznych). W szczególności surowy ciąg znaków nie może zakończyć się pojedynczym ukośnikiem wstecznym (ponieważ ukośnik wsteczny ucieknie z następujący znak cytatu). Zauważ również, że pojedynczy ukośnik wsteczny followed przez nowy wiersz jest interpretowany jako te dwa znaki jako część ciąg, nie jako kontynuacja linii.

 1
Author: Lorenzo Gatti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 16:05:34