从 regex 上的 python 文档中,关于 '\'
字符:
解决方案是对正则表达式模式使用 Python 的原始字符串表示法;在以 'r' 为前缀的字符串文字中,反斜杠不会以任何特殊方式处理。所以 r"\n" 是一个包含 '\' 和 'n' 的两个字符的字符串,而 "\n" 是一个包含换行符的一个字符的字符串。通常,模式将使用这种原始字符串表示法在 Python 代码中表示。
这个原始字符串表示法是什么?如果您使用原始字符串格式,这是否意味着 "*"
被视为文字字符而不是零个或多个指示符?这显然是不对的,否则正则表达式将完全失去它的力量。但是,如果它是一个原始字符串,如果 "\n"
实际上是一个反斜杠和一个 "n"
,它如何识别换行符?
我不跟。
编辑赏金:
我试图了解原始字符串正则表达式如何匹配换行符、制表符和字符集,例如,\w
表示单词或 \d
表示数字或所有诸如此类,如果原始字符串模式不能将反斜杠识别为普通人物。我真的可以举一些很好的例子。
Zarkonnen 的回答确实回答了您的问题,但没有直接回答。让我试着更直接一些,看看我能不能从 Zarkonnen 那里抢到赏金。
如果您停止使用术语“原始字符串正则表达式”和“原始字符串模式”,您可能会发现这更容易理解。这些术语将两个独立的概念混为一谈:Python 源代码中特定字符串的表示,以及该字符串表示的正则表达式。
事实上,将它们视为两种不同的编程语言是有帮助的,每种语言都有自己的语法。 Python 语言有源代码,其中包括构建具有特定内容的字符串,并调用正则表达式系统。正则表达式系统具有驻留在字符串对象中并匹配字符串的源代码。两种语言都使用反斜杠作为转义字符。
首先,要了解字符串是一个字符序列(即字节或Unicode 代码点;这里的区别并不重要)。在 Python 源代码中有多种表示字符串的方法。原始字符串只是这些表示形式之一。如果两种表示产生相同的字符序列,它们会产生相同的行为。
想象一个 2 字符的字符串,由反斜杠字符后跟 n 字符组成。如果你知道反斜杠的字符值是 92,n 是 110,那么这个表达式会生成我们的字符串:
s = chr(92)+chr(110)
print len(s), s
2 \n
传统的 Python 字符串表示法 "\n"
不会生成此字符串。相反,它会生成一个带有换行符的单字符字符串。 Python docs 2.4.1. String literals 表示“反斜杠 (\) 字符用于转义具有特殊含义的字符,例如换行符、反斜杠本身或引号字符。”
s = "\n"
print len(s), s
1
(注意在这个例子中换行符是不可见的,但是如果你仔细看,你会在“1”之后看到一个空行。)
为了得到我们的两个字符的字符串,我们必须使用另一个反斜杠字符来转义原始反斜杠字符的特殊含义:
s = "\\n"
print len(s), s
2 \n
如果您想表示其中包含许多 反斜杠 字符的字符串怎么办? Python docs 2.4.1. String literals 继续,“字符串文字可以选择以字母 'r' 或 'R' 作为前缀;此类字符串称为 原始字符串,并使用不同的规则来解释反斜杠转义序列。”这是我们的两个字符的字符串,使用原始字符串表示:
s = r"\n"
print len(s), s
2 \n
所以我们有三种不同的字符串表示,都给出相同的字符串或字符序列:
print chr(92)+chr(110) == "\\n" == r"\n"
True
现在,让我们转向正则表达式。 Python docs, 7.2. re
— Regular expression operations 说,“正则表达式使用反斜杠字符 ('\') 来表示特殊形式或允许使用特殊字符而不调用它们的特殊含义。这与 Python 出于相同目的使用相同字符相冲突字符串文字..."
如果你想要一个匹配换行符的 Python 正则表达式对象,那么你需要一个 2 字符的字符串,由 反斜杠 字符后跟 n 字符组成。以下代码行都将 prog
设置为识别换行符的正则表达式对象:
prog = re.compile(chr(92)+chr(110))
prog = re.compile("\\n")
prog = re.compile(r"\n")
那么为什么是"Usually patterns will be expressed in Python code using this raw string notation."?因为正则表达式通常是静态字符串,可以方便地表示为字符串文字。从可用的不同字符串文字符号中,当正则表达式包含 反斜杠 字符时,原始字符串是一个方便的选择。
问题
问:表达式 re.compile(r"\s\tWord")
怎么样? A:将字符串从正则表达式编译中分离出来,分别理解,更容易理解。
s = r"\s\tWord"
prog = re.compile(s)
字符串 s
包含八个字符:反斜杠、s、反斜杠、t和然后是四个字符 Word
。
问:制表符和空格字符会怎样? A:在 Python 语言级别,字符串 s
没有 tab 和 空格 字符。它以四个字符开头:反斜杠、s、反斜杠、t。与此同时,正则表达式系统将该字符串视为正则表达式语言中的源代码,这意味着“匹配由空格字符、制表符和四个字符 Word
组成的字符串。
问:如果将其视为 backlash-s 和 backslash-t,您如何匹配它们? A:如果“you”和“that”这两个词更具体,也许问题会更清楚:正则表达式系统如何匹配表达式 backlash-s 和 backslash-t?作为“任何空白字符”和“制表符”。
问:或者如果你有 3 个字符的字符串 backslash-n-newline 怎么办? A:在 Python 语言中,3 个字符的字符串 backslash-n-newline 可以表示为常规字符串 "\\n\n"
,或原始加常规字符串 r"\n" "\n"
,或其他方式。正则表达式系统在找到任意两个连续的 newline 字符时匹配 3 个字符的字符串 backslash-n-newline。
注意:所有示例和文档引用均指向 Python 2.7。
更新:合并了@Vladislav Zorov 和@m.buettner 的回答以及@Aerovistae 的后续问题的澄清。
这些问题中的大多数都有很多词,也许很难找到您特定问题的答案。
如果您使用常规字符串并将“\t”之类的模式传递给 RegEx 解析器,Python 会将该文字转换为包含制表符字节(0x09)的缓冲区。
如果您使用原始字符串并将 r"\t" 之类的模式传递给 RegEx 解析器,Python 不会进行任何解释,它会创建一个包含两个字节的缓冲区:'\' 和 't'。 (0x5c,0x74)。
RegEx 解析器知道如何处理序列 '\t' - 它会将其与制表符匹配。它还知道如何处理 0x09 字符——它也匹配一个制表符。在大多数情况下,结果将无法区分。
因此,了解正在发生的事情的关键是认识到这里使用了两个解析器。第一个是 Python 解析器,它将您的字符串文字(或原始字符串文字)转换为字节序列。第二个是 Python 的正则表达式解析器,它将字节序列转换为已编译的正则表达式。
使用普通字符串编写包含 \
的正则表达式的问题是您最终必须为每个 \
编写 \\
。所以字符串字面量 "stuff\\things"
和 r"stuff\things"
产生相同的字符串。如果您想编写与反斜杠匹配的正则表达式,这将特别有用。
使用普通字符串,匹配字符串 \
的正则表达式将是 "\\\\"
!
为什么?因为我们必须对 \
进行两次转义:一次用于正则表达式语法,一次用于字符串语法。
您可以使用三引号来包含换行符,如下所示:
r'''stuff\
things'''
请注意,通常,python 会将 \
-newline 视为行继续,但在原始字符串中并非如此。另请注意,反斜杠仍会转义原始字符串中的引号,但会保留在其自身中。因此原始字符串文字 r"\""
产生字符串 \"
。这意味着您不能以反斜杠结束原始字符串文字。
有关详细信息,请参阅 the lexical analysis section of the Python documentation。
r'''something<enter>onnewline'''
。 <enter>
表示按回车。不完全漂亮,所以也许你可以在这里使用字符串连接?
r"stuff\"
是一个错误。
re.match(r'1\n2', string)
表示 re.match('1\\n2', string)
,因此 \n
不是由 python 解释,而是由正则表达式解析器解释 - 它实际上给出与简单 re.match('1\n2', string)
相同的结果,因为正则表达式解析器将处理由 python 给出的未转义换行符就好了(至少在我的 Python 3 测试中)
您似乎在为 RegEx 不是 Python 的一部分,而是一种具有自己的解析器和编译器的不同编程语言的想法而苦苦挣扎。原始字符串可帮助您将 RegEx 的“源代码”安全地提供给 RegEx 解析器,然后解析器将为 \d
、\w
、\n
等字符序列分配含义......
问题的存在是因为 Python 和 RegExps 使用 \
作为转义字符,顺便说一下,这是一个巧合 - 有些语言带有其他转义字符(例如“`n”作为换行符,但即使在那里你也必须使用“ \n" 在正则表达式中)。优点是您不需要区分这些语言中的原始字符串和非原始字符串,它们不会同时尝试转换文本并对其进行处理,因为它们对不同的转义序列做出反应。
相关的 Python 手册部分(“字符串和字节文字”)对原始字符串文字有明确的解释:
字符串和字节文字都可以选择以字母“r”或“R”作为前缀;此类字符串称为原始字符串,并将反斜杠视为文字字符。因此,在字符串文字中,原始字符串中的 '\U' 和 '\u' 转义不会被特殊处理。鉴于 Python 2.x 的原始 unicode 文字的行为与 Python 3.x 的不同,不支持 'ur' 语法。 3.3 版中的新功能:添加了原始字节文字的“rb”前缀作为“br”的同义词。 3.3 版中的新功能:重新引入了对 unicode 传统文字 (u'value') 的支持,以简化双 Python 2.x 和 3.x 代码库的维护。有关详细信息,请参阅 PEP 414。在三引号字符串中,允许(并保留)未转义的换行符和引号,除非一行中的三个未转义的引号终止字符串。 (“引号”是用于打开字符串的字符,即 ' 或 "。)除非存在 'r' 或 'R' 前缀,否则字符串中的转义序列将根据与标准 C 使用的规则类似的规则进行解释. 识别的转义序列有: 转义序列 含义 注释 \newline 反斜杠和换行符被忽略 \ 反斜杠 () \' 单引号 (') \" 双引号 (") \a ASCII Bell (BEL) \b ASCII Backspace (BS) \ f ASCII 换页符 (FF) \n ASCII 换行符 (LF) \r ASCII 回车符 (CR) \t ASCII 水平制表符 (TAB) \v ASCII 垂直制表符 (VT) \ooo 八进制值 ooo (1,3) 的字符 \ xhh 具有十六进制值 hh 的字符 (2,3) 仅在字符串文字中识别的转义序列有: 转义序列 含义 注释 \N{name} Unicode 数据库中名为 name 的字符 (4) \uxxxx 具有 16 位十六进制值 xxxx 的字符 ( 5) \Uxxxxxxxx 具有 32 位十六进制值的字符 xxxxxxxx (6) 注意:与标准 C 中一样,最多接受三个八进制数字。与标准 C 不同,只需要两个十六进制数字d。在字节文字中,十六进制和八进制转义表示具有给定值的字节。在字符串文字中,这些转义表示具有给定值的 Unicode 字符。在 3.3 版更改:添加了对名称别名 [1] 的支持。可以使用此转义序列对构成代理对部分的各个代码单元进行编码。需要四个十六进制数字。任何 Unicode 字符都可以通过这种方式编码,但如果 Python 编译为使用 16 位代码单元(默认值),则基本多语言平面 (BMP) 之外的字符将使用代理对进行编码。正好需要八个十六进制数字。与标准 C 不同,所有无法识别的转义序列都保留在字符串中,即,反斜杠保留在字符串中。 (此行为在调试时很有用:如果转义序列输入错误,结果输出更容易被识别为损坏。)还需要注意的是,仅在字符串文字中识别的转义序列属于无法识别的字节转义类别文字。即使在原始字符串中,字符串引号也可以用反斜杠转义,但反斜杠保留在字符串中;例如,r"\"" 是由两个字符组成的有效字符串文字:反斜杠和双引号;r"\" 不是有效的字符串文字(即使原始字符串也不能以奇数个反斜杠结尾)。具体来说,原始字符串不能以单个反斜杠结尾(因为反斜杠会转义后面的引号字符)。另请注意,单个反斜杠后跟换行符被解释为这两个字符作为字符串的一部分,而不是作为续行.
\n
是 Python 中的转义序列
\w
是 (Python) 正则表达式中的特殊序列
他们看起来像在同一个家庭,但他们不是。原始字符串表示法将影响转义序列,但不会影响正则表达式特殊序列。
有关转义序列的更多信息,请搜索“\newline”https://docs.python.org/3/reference/lexical_analysis.html
有关特殊序列的更多信息:搜索“\number”https://docs.python.org/3/library/re.html
原始字符串不会影响 python 正则表达式中的特殊序列,例如 \w、\d。它只影响转义序列,例如 \n。所以大多数时候我们在前面写 r 与否都没有关系。
我认为这是大多数初学者正在寻找的答案。
s
结尾,而\t
将成为一个制表符。现在只有两个字符被交给正则表达式引擎。虽然引擎可能仍然能够匹配制表符,但它现在会尝试匹配它前面的s
。ord(92)
只会引发TypeError
,因为92
不是字符串。您可能指的是chr(92)
(或者可能是unichr(92)
)?