Python regex - prefiks r


87

Czy ktoś może wyjaśnić, dlaczego przykład 1 poniżej działa, kiedy rprzedrostek nie jest używany? Pomyślałem, że rprzedrostek musi być używany zawsze, gdy używane są sekwencje ucieczki. Przykład 2 i przykład 3 demonstrują to.

# example 1
import re
print (re.sub('\s+', ' ', 'hello     there      there'))
# prints 'hello there there' - not expected as r prefix is not used

# example 2
import re
print (re.sub(r'(\b\w+)(\s+\1\b)+', r'\1', 'hello     there      there'))
# prints 'hello     there' - as expected as r prefix is used

# example 3
import re
print (re.sub('(\b\w+)(\s+\1\b)+', '\1', 'hello     there      there'))
# prints 'hello     there      there' - as expected as r prefix is not used

Odpowiedzi:


86

Ponieważ \rozpoczynaj sekwencje specjalne tylko wtedy, gdy są poprawnymi sekwencjami ucieczki.

>>> '\n'
'\n'
>>> r'\n'
'\\n'
>>> print '\n'


>>> print r'\n'
\n
>>> '\s'
'\\s'
>>> r'\s'
'\\s'
>>> print '\s'
\s
>>> print r'\s'
\s

O ile nie ma przedrostka „r” lub „R”, sekwencje specjalne w łańcuchach są interpretowane zgodnie z regułami podobnymi do reguł stosowanych w standardzie C. Rozpoznawane sekwencje specjalne to:

Escape Sequence   Meaning Notes
\newline  Ignored  
\\    Backslash (\)    
\'    Single quote (')     
\"    Double quote (")     
\a    ASCII Bell (BEL)     
\b    ASCII Backspace (BS)     
\f    ASCII Formfeed (FF)  
\n    ASCII Linefeed (LF)  
\N{name}  Character named name in the Unicode database (Unicode only)  
\r    ASCII Carriage Return (CR)   
\t    ASCII Horizontal Tab (TAB)   
\uxxxx    Character with 16-bit hex value xxxx (Unicode only) 
\Uxxxxxxxx    Character with 32-bit hex value xxxxxxxx (Unicode only) 
\v    ASCII Vertical Tab (VT)  
\ooo  Character with octal value ooo
\xhh  Character with hex value hh

Nigdy nie polegaj na surowych ciągach dla literałów ścieżki, ponieważ surowe ciągi mają pewne dość osobliwe wewnętrzne mechanizmy, o których wiadomo, że ugryzły ludzi w tyłek:

Gdy obecny jest przedrostek „r” lub „R”, znak następujący po ukośniku odwrotnym jest zawarty w ciągu bez zmiany, a wszystkie ukośniki odwrotne pozostają w ciągu. Na przykład, literał ciągu r"\n"składa się z dwóch znaków: ukośnika odwrotnego i małej litery „n”. Cudzysłowy łańcuchowe mogą być poprzedzone ukośnikiem odwrotnym, ale ukośnik odwrotny pozostaje w ciągu; na przykład r"\""jest prawidłowym literałem ciągu składającym się z dwóch znaków: ukośnika odwrotnego i cudzysłowu; r"\"nie jest prawidłowym literałem ciągu (nawet nieprzetworzony ciąg nie może kończyć się nieparzystą liczbą odwrotnych ukośników). Konkretnie, nieprzetworzony ciąg nie może kończyć się pojedynczym ukośnikiem odwrotnym (ponieważ ukośnik odwrotny mógłby uciec od następującego cudzysłowu). Zauważ również, że pojedynczy lewy ukośnik, po którym następuje nowa linia, jest interpretowany jako te dwa znaki jako część ciągu,

Aby lepiej zilustrować ten ostatni punkt:

>>> r'\'
SyntaxError: EOL while scanning string literal
>>> r'\''
"\\'"
>>> '\'
SyntaxError: EOL while scanning string literal
>>> '\''
"'"
>>> 
>>> r'\\'
'\\\\'
>>> '\\'
'\\'
>>> print r'\\'
\\
>>> print r'\'
SyntaxError: EOL while scanning string literal
>>> print '\\'
\

Jako drobna poprawka '\s'(like r'\s') jest również reprezentowany jako '\\s', ponieważ '\s'nie jest rozpoznawaną sekwencją ucieczki.
Massood Khaari,

@MassoodKhaari Przysięgam, że wynik był poprawny, kiedy pisałem tę odpowiedź ... Naprawiono.
Esteban Küber,

1
8 lat z pewnością uzasadnia magiczną zmianę w zachowaniu pytona. : D
Massood Khaari,

34

„r” oznacza „nieprzetworzony ciąg znaków”, tj. Znaki z ukośnikiem odwrotnym są traktowane dosłownie, zamiast oznaczać specjalne traktowanie następującego znaku.

http://docs.python.org/reference/lexical_analysis.html#literals

więc '\n'jest pojedynczym znakiem nowej linii
i r'\n'składa się z dwóch znaków - ukośnika odwrotnego i litery 'n'
innym sposobem zapisania tego byłoby to, '\\n'że pierwszy ukośnik odwrotny zastępuje drugi

równoważny sposób pisania tego

print (re.sub(r'(\b\w+)(\s+\1\b)+', r'\1', 'hello     there      there'))

jest

print (re.sub('(\\b\\w+)(\\s+\\1\\b)+', '\\1', 'hello     there      there'))

Ze względu na sposób, w jaki Python traktuje znaki, które nie są prawidłowymi znakami ucieczki, nie wszystkie te podwójne ukośniki odwrotne są konieczne - np. '\s'=='\\s'Jednak to samo nie dotyczy '\b'i '\\b'. Wolę być wyraźny i podwoić wszystkie ukośniki.


5

Nie wszystkie sekwencje zawierające ukośniki odwrotne są sekwencjami ucieczki. \ti \fsą na przykład, ale \snie są. W nie surowym literale łańcuchowym każdy \element , który nie jest częścią sekwencji ucieczki, jest postrzegany jako po prostu kolejny \:

>>> "\s"
'\\s'
>>> "\t"
'\t'

\b jest sekwencją ucieczki, więc przykład 3 zawodzi. (I tak, niektórzy uważają to zachowanie za raczej niefortunne).


Dokładnie. Chociaż @JT, polecam użycie '\\ s' lub r '\ s', albo prawdopodobnie przypadkowo trafisz na sekwencje ucieczki, których nie chciałeś.
Blair Conrad,

Rzeczywiście: zawsze używaj surowych literałów ciągów, gdy chcesz, aby ciąg zawierał ukośniki odwrotne (w przeciwieństwie do rzeczywistych sekwencji ucieczki).
Thomas Wouters,

@Thomas: rnadal wymyka niektóre sekwencje, gdy pojawiają się na końcu łańcucha: r"\"jest niepoprawne, aby to zrobić, musisz to zrobić "\\". Jeśli tak r"\\", otrzymasz \\ wydrukowany ( "\\\\"ciąg). Uważaj z tym.
Esteban Küber,

Tak, surowe literały ciągów nie mogą kończyć się pojedynczym `\`.
Thomas Wouters,

@ Blair / Thomas: dzięki - to była ogólna zasada, której się trzymałem, a która przede wszystkim mnie zdezorientowała! ... wszystko jest już jasne, dzięki wszystkim. Chociaż przestrzegając tej reguły ... podczas odczytywania wzorca z pliku zwykłego tekstu, w jaki sposób wzorzec zostałby przekazany jako nieprzetworzony ciąg literału?
JT.


0

Sprawdź poniższy przykład:

print r"123\n123" 
#outputs>>>
123\n123


print "123\n123"
#outputs>>>
123
123
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.