Python正则表达式-r前缀

109

有人能解释一下为什么示例1没有使用r前缀也可以正常工作吗? 我之前认为只要使用转义序列就必须加上r前缀。 示例2和示例3证明了这一点。

# 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

我认为我已经很好地解释了为什么在这里需要原始字符串:https://dev59.com/L3VC5IYBdhLWcg3weBE-#73068412 - Charlie Parker
5个回答

106

因为 \ 只有在它们是有效的转义序列时才开始转义。

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


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

Unless an 'r' or 'R' prefix is present, escape sequences in strings are interpreted according to rules similar to those used by Standard C. The recognized escape sequences are:

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
不要仅依赖原始字符串来表示路径文字,因为原始字符串有一些相当“奇特”的内部机制,已经咬了很多人的屁股。当存在“r”或“R”前缀时,反斜杠后面的字符将不加改变地包含在字符串中,并且所有反斜杠都会留在字符串中。例如,字符串字面量r"\n"由两个字符组成:一个反斜杠和一个小写字母"n"。字符串引号可以用反斜杠转义,但反斜杠仍然留在字符串中;例如,r"\""是一个有效的字符串文字,由两个字符组成:一个反斜杠和一个双引号;r"\"不是一个有效的字符串文字(即使原始字符串不能以奇数个反斜杠结尾)。具体而言,原始字符串不能以单个反斜杠结尾(因为反斜杠会转义以下的引号字符)。还要注意,一个反斜杠后跟换行符被解释为字符串的一部分,而不是作为行继续符。为了更好地说明这一点:
>>> 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 '\\'
\

作为一个小修复,'\s'(例如 r'\s')也被表示为'\\s',因为'\s'不是一个被识别的转义序列。 - Masood Khaari
@MassoodKhaari 我敢肯定当我写这个答案时输出是正确的...已修复。 - Esteban Küber
1
8年的时间肯定证明了Python行为上的神奇变化。 :D - Masood Khaari

49

'r'代表原始字符串,即反斜杠字符被视为字面意义而不是表示后面字符的特殊处理。

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

所以'\n'表示一个换行符
r'\n'则是两个字符——反斜杠和字母'n'
另一种写法是'\\n',因为第一个反斜杠转义了第二个

等价的写法

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

由于Python处理无效转义字符的方式,不是所有双反斜杠都是必需的 - 例如'\s'=='\\s',但对于'\b''\\b'不成立。我更喜欢明确地加倍所有反斜杠。

6
并非所有涉及反斜杠的序列都是转义序列。例如,\t\f是转义序列,但\s不是。在非原始字符串字面值中,任何不是转义序列的\都被视为另一个\
>>> "\s"
'\\s'
>>> "\t"
'\t'

\b是一个转义序列,但是第三个示例失败了。(是的,有些人认为这种行为相当不幸。)


没错。不过,@JT,我建议使用 '\s' 或 r'\s',否则你可能会无意中触发一些你不想要的转义序列。 - Blair Conrad
确实:当您希望字符串包含反斜杠(而不是实际想要转义序列)时,请始终使用原始字符串字面值。 - Thomas Wouters
@Thomas:r 在字符串末尾仍然会转义一些序列:r"\" 是无效的,要实现这个功能,你需要使用 "\\"。如果你使用 r"\\",你将得到一个打印出的 \\"\\\\" 字符串)。请小心处理这个问题。 - Esteban Küber
是的,原始字符串字面量不能以单个 \\ 结尾。 - Thomas Wouters
@Blair/Thomas:谢谢 - 这是我一开始遵循的通用规则,让我感到困惑!...现在一切都清楚了,谢谢大家。虽然按照这个规则进行操作...当从纯文本文件中读取模式时,该如何将模式作为原始字面字符串传递? - JT.
@JT,如果我理解问题正确的话,您只需在纯文本文件中放置\s即可 - 当您读取它时,不会对字符串内容进行任何解释。 - Blair Conrad

1

Try that:

a = '\''
'
a = r'\''
\'
a = "\'"
'
a = r"\'"
\'

1
请查看下面的例子:
print r"123\n123" 
#outputs>>>
123\n123


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接