Python regex - prefixo r


87

Alguém pode explicar por que o exemplo 1 abaixo funciona, quando o rprefixo não é usado? Achei que o rprefixo deve ser usado sempre que sequências de escape são usadas. Os exemplos 2 e 3 demonstram isso.

# 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

Respostas:


86

Porque \comece as sequências de escape apenas quando forem sequências 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 um prefixo 'r' ou 'R' esteja presente, as sequências de escape em strings são interpretadas de acordo com regras semelhantes às usadas pelo Padrão C. As sequências de escape reconhecidas são:

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 confie em strings brutas para literais de caminho, pois as strings brutas têm alguns funcionamentos internos bastante peculiares , conhecidos por terem mordido as pessoas na bunda:

Quando um prefixo "r" ou "R" está presente, um caractere após uma barra invertida é incluído na string sem alteração e todas as barras invertidas são deixadas na string. Por exemplo, a string literal r"\n"consiste em dois caracteres: uma barra invertida e um "n" minúsculo. As aspas de string podem ser escapadas com uma barra invertida, mas a barra invertida permanece na string; por exemplo, r"\""é um literal de string válido que consiste em dois caracteres: uma barra invertida e uma aspa dupla; r"\"não é um literal de string válido (mesmo uma string bruta não pode terminar com um número ímpar de barras invertidas). Especificamente, uma string bruta não pode terminar em uma única barra invertida (uma vez que a barra invertida escaparia do seguinte caractere de aspas). Observe também que uma única barra invertida seguida por uma nova linha é interpretada como esses dois caracteres como parte da string,

Para ilustrar melhor este último ponto:

>>> 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 uma pequena correção, '\s'(like r'\s') também é representado como '\\s', devido a '\s'não ser uma sequência de escape reconhecida.
Massood Khaari

@MassoodKhaari Eu juro que a saída estava correta quando escrevi esta resposta ... Corrigido.
Esteban Küber

1
8 anos certamente justificam a mudança mágica no comportamento do python. : D
Massood Khaari

34

o 'r' significa que o seguinte é uma "string bruta", ou seja. os caracteres de barra invertida são tratados literalmente em vez de significar um tratamento especial do caractere a seguir.

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

o mesmo '\n'ocorre com uma única nova linha
e r'\n'dois caracteres - uma barra invertida e a letra 'n'
outra maneira de escrever seria '\\n'porque a primeira barra invertida escapa da segunda

uma maneira equivalente de escrever isso

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

Devido à maneira como o Python trata os caracteres que não são caracteres de escape válidos, nem todas essas barras invertidas duplas são necessárias - por exemplo, '\s'=='\\s'o mesmo não é verdadeiro para '\b'e '\\b'. Minha preferência é ser explícito e dobrar todas as barras invertidas.


5

Nem todas as sequências que envolvem barras invertidas são sequências de escape. \te \fsão, por exemplo, mas \snão é. Em um literal de string não bruto, qualquer um \que não faça parte de uma sequência de escape é visto como apenas outro \:

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

\b é uma sequência de escape, no entanto, o exemplo 3 falha. (E sim, algumas pessoas consideram esse comportamento um tanto infeliz.)


Exatamente. Embora, @JT, eu recomende usar '\\ s' ou r '\ s', ou você provavelmente irá acidentalmente atingir algumas sequências de escape que não queria.
Blair Conrad

Na verdade: sempre use literais de string brutos quando quiser que a string contenha barras invertidas (em vez de realmente querer as sequências de escape.)
Thomas Wouters

@Thomas: rainda escapa algumas sequências quando aparecem no final da string: r"\"é inválido, para fazer isso você tem que fazer "\\". Se o fizer r"\\", obterá uma \\ ( "\\\\"string) impressa . Cuidado com isso.
Esteban Küber

Sim, os literais de string bruta não podem terminar em um único `\`.
Thomas Wouters de

@ Blair / Thomas: obrigado - essa era a regra geral que eu estava seguindo e que me deixou confuso em primeiro lugar! ... tudo está claro agora, obrigado a todos. Embora seguindo esta regra ... ao ler o padrão de um arquivo de texto simples, como o padrão seria transmitido como uma string literal bruta?
JT.


0

Veja o exemplo abaixo:

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


print "123\n123"
#outputs>>>
123
123
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.