Python regex - prefijo r


87

¿Alguien puede explicar por qué funciona el ejemplo 1 a continuación, cuando rno se usa el prefijo? Pensé que el rprefijo debe usarse siempre que se usen secuencias de escape. El ejemplo 2 y el ejemplo 3 demuestran esto.

# 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

Respuestas:


86

Porque \comienzan las secuencias de escape solo cuando son secuencias de escape válidas.

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


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

A menos que esté presente un prefijo 'r' o 'R', las secuencias de escape en cadenas se interpretan de acuerdo con reglas similares a las utilizadas por el Estándar C. Las secuencias de escape reconocidas son:

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

Nunca confíe en cadenas sin procesar para los literales de ruta, ya que las cadenas sin procesar tienen un funcionamiento interno bastante peculiar , que se sabe que ha mordido a la gente en el trasero:

Cuando hay un prefijo "r" o "R", un carácter que sigue a una barra invertida se incluye en la cadena sin cambios, y todas las barras invertidas se dejan en la cadena. Por ejemplo, la cadena literal r"\n"consta de dos caracteres: una barra invertida y una "n" minúscula. Las comillas de cadena se pueden escapar con una barra invertida, pero la barra invertida permanece en la cadena; por ejemplo, r"\""es un literal de cadena válido que consta de dos caracteres: una barra invertida y una comilla doble; r"\"no es un literal de cadena válido (incluso una cadena sin formato no puede terminar en un número impar de barras invertidas). Específicamente, una cadena sin formato no puede terminar en una sola barra invertida (ya que la barra invertida escaparía del siguiente carácter de comillas). Tenga en cuenta también que una sola barra invertida seguida de una nueva línea se interpreta como esos dos caracteres como parte de la cadena,

Para ilustrar mejor este último 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 '\\'
\

Como solución menor, '\s'(like r'\s') también se representa como '\\s', debido a que '\s'no es una secuencia de escape reconocida.
Massood Khaari

@MassoodKhaari Juraría que el resultado era correcto cuando escribí esta respuesta ... Corregido.
Esteban Küber

1
Ciertamente, 8 años justifican el cambio mágico en el comportamiento de las pitones. : D
Massood Khaari

34

la 'r' significa que lo siguiente es una "cadena sin formato", es decir. los caracteres de barra invertida se tratan literalmente en lugar de significar un tratamiento especial del siguiente carácter.

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

por lo que '\n'es una sola línea nueva
y r'\n'tiene dos caracteres: una barra invertida y la letra 'n';
otra forma de escribirlo sería '\\n'porque la primera barra invertida escapa a la segunda

una forma equivalente de escribir esto

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

es

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

Debido a la forma en que Python trata los caracteres que no son caracteres de escape válidos, no todas esas barras diagonales inversas dobles son necesarias; por ejemplo, '\s'=='\\s'sin embargo, no ocurre lo mismo con '\b'y '\\b'. Mi preferencia es ser explícito y duplicar todas las barras invertidas.


5

No todas las secuencias que incluyen barras invertidas son secuencias de escape. \ty lo \fson, por ejemplo, pero \sno lo son. En un literal de cadena no sin formato, cualquiera \que no sea parte de una secuencia de escape se considera simplemente otro \:

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

\b es una secuencia de escape, sin embargo, el ejemplo 3 falla. (Y sí, algunas personas consideran este comportamiento bastante desafortunado).


Exactamente. Aunque, @JT, recomiendo usar '\\ s' o r '\ s', o probablemente sin darte cuenta encontrarás algunas secuencias de escape que no querías.
Blair Conrad

De hecho: siempre use literales de cadena sin procesar cuando desee que la cadena contenga barras invertidas (en lugar de querer las secuencias de escape)
Thomas Wouters

@Thomas: rtodavía se escapa de algunas secuencias cuando aparecen al final de la cadena: r"\"no es válido, para hacer eso tienes que hacerlo "\\". Si lo hace r"\\", obtiene una \\ ( "\\\\"cadena) impresa . Ten cuidado con eso.
Esteban Küber

Sí, los literales de cadena sin formato no pueden terminar en un solo `\`.
Thomas Wouters

@ Blair / Thomas: gracias - ¡esta era la regla general que estaba siguiendo y que me confundió en primer lugar! ... todo está claro ahora, gracias a todos. Aunque al seguir esta regla ... al leer el patrón de un archivo de texto sin formato, ¿cómo se pasaría el patrón como una cadena literal sin formato?
JT.


0

Consulte el siguiente ejemplo:

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


print "123\n123"
#outputs>>>
123
123
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.