Python regex - prefisso r


89

Qualcuno può spiegare perché l'esempio 1 di seguito funziona, quando il rprefisso non viene utilizzato? Ho pensato che il rprefisso deve essere utilizzato ogni volta che vengono utilizzate le sequenze di escape. L'esempio 2 e l'esempio 3 lo dimostrano.

# 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

Risposte:


88

Perché \iniziano le sequenze di escape solo quando sono sequenze di escape valide.

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


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

A meno che non sia presente un prefisso "r" o "R", le sequenze di escape nelle stringhe vengono interpretate secondo regole simili a quelle utilizzate dallo Standard C. Le sequenze di escape riconosciute sono:

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

Non fare mai affidamento su stringhe grezze per i letterali del percorso, poiché le stringhe grezze hanno alcuni meccanismi interni piuttosto peculiari , noti per aver morso le persone nel culo:

Quando è presente un prefisso "r" o "R", un carattere che segue una barra rovesciata viene incluso nella stringa senza modifiche e tutte le barre rovesciate vengono lasciate nella stringa. Ad esempio, la stringa letterale è r"\n"composta da due caratteri: una barra rovesciata e una "n" minuscola. Le virgolette di stringa possono essere precedute da una barra rovesciata, ma la barra rovesciata rimane nella stringa; ad esempio, r"\""è una stringa letterale valida composta da due caratteri: una barra rovesciata e virgolette doppie; r"\"non è una stringa letterale valida (anche una stringa non elaborata non può terminare con un numero dispari di barre rovesciate). In particolare, una stringa non elaborata non può terminare con una singola barra rovesciata (poiché la barra rovesciata sfuggirebbe al seguente carattere di virgolette). Nota anche che una singola barra rovesciata seguita da una nuova riga viene interpretata come quei due caratteri come parte della stringa,

Per illustrare meglio quest'ultimo punto:

>>> 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 '\\'
\

Come correzione minore, '\s'(like r'\s') è anche rappresentato come '\\s', poiché '\s'non è una sequenza di escape riconosciuta.
Massood Khaari

@ MassoodKhaari Giurerei che l'output fosse corretto quando ho scritto questa risposta ... Risolto.
Esteban Küber

1
8 anni giustificano sicuramente il magico cambiamento nel comportamento del pitone. : D
Massood Khaari

35

la 'r' significa che quanto segue è una "stringa grezza", ad es. i caratteri backslash vengono trattati letteralmente invece di indicare un trattamento speciale del carattere successivo.

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

quindi '\n'è una singola nuova riga
ed r'\n'è composta da due caratteri: una barra rovesciata e la lettera 'n'
un altro modo per scriverla sarebbe'\\n' perché il primo backslash sfugge al secondo

un modo equivalente per scrivere questo

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

è

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

A causa del modo in cui Python tratta i caratteri che non sono caratteri di escape validi, non tutti questi doppi backslash sono necessari - ad esempio, '\s'=='\\s'tuttavia lo stesso non è vero per '\b'e '\\b'. La mia preferenza è di essere esplicito e raddoppiare tutte le barre rovesciate.


6

Non tutte le sequenze che coinvolgono i backslash sono sequenze di escape. \te \fsono, per esempio, ma \snon lo sono. In un letterale stringa non grezzo, tutto \ciò che non fa parte di una sequenza di escape viene visto come un altro \:

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

\b è una sequenza di escape, tuttavia, quindi l'esempio 3 fallisce. (E sì, alcune persone considerano questo comportamento piuttosto sfortunato.)


Esattamente. Anche se, @JT, ti consiglio di usare '\\ s' o r '\ s', o probabilmente colpirai inavvertitamente alcune sequenze di escape che non intendevi.
Blair Conrad,

Infatti: usa sempre stringhe letterali non elaborate quando vuoi che la stringa contenga barre rovesciate (invece di volere effettivamente le sequenze di escape).
Thomas Wouters

@Thomas: rsfugge ancora alcune sequenze quando compaiono alla fine della stringa: r"\"non è valido, per farlo devi farlo "\\". Se lo fai r"\\", ottieni una \\ ( "\\\\"stringa) stampata . Stai attento con quello.
Esteban Küber,

Sì, le stringhe letterali non elaborate non possono terminare con un singolo "\".
Thomas Wouters,

@ Blair / Thomas: grazie - questa era la regola generale che stavo seguendo che mi ha confuso in primo luogo! ... ora è tutto chiaro, grazie a tutti. Sebbene nel seguire questa regola ... durante la lettura del pattern da un file di testo semplice, come sarebbe passato il pattern come stringa letterale grezza?
JT.


0

Controlla l'esempio seguente:

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


print "123\n123"
#outputs>>>
123
123
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.