Python Regex 转义运算符\in 替换和原始字符串

标签 python regex substitution backslash rawstring

我不理解 python 正则表达式中 scape 运算符\与原始字符串 r' 一起运行的逻辑。 感谢您提供一些帮助。

代码:

import re
text=' esto  .es  10  . er - 12 .23 with [  and.Other ] here is more ; puntuation'
print('text0=',text)
text1 = re.sub(r'(\s+)([;:\.\-])', r'\2', text)
text2 = re.sub(r'\s+\.', '\.', text)
text3 = re.sub(r'\s+\.', r'\.', text)
print('text1=',text1)
print('text2=',text2)
print('text3=',text3)

理论说: 反斜杠字符 ('\') 表示特殊形式或允许使用特殊字符而不调用它们的特殊含义。

就此问题末尾提供的链接所解释的而言,r' 表示原始字符串,即符号没有特殊含义,它保持原样。

所以在上面的正则表达式中,我希望 text2 和 text3 不同,因为替换文本是“.”在文本 2 中,即句号,而(原则上)文本 3 中的替换文本是 r'.'这是一个原始字符串,即应该出现的字符串、反斜杠和句点。但它们的结果是一样的:

结果是:

text0=  esto  .es  10  . er - 12 .23 with [  and.Other ] here is more ; puntuation
text1=  esto.es  10. er- 12.23 with [  and.Other ] here is more; puntuation
text2=  esto\.es  10\. er - 12\.23 with [  and.Other ] here is more ; puntuation
text3=  esto\.es  10\. er - 12\.23 with [  and.Other ] here is more ; puntuation
#text2=text3 but substitutions are not the same r'\.' vs '\.'

在我看来,r' 在替换部分和反斜杠中的工作方式不同。另一方面,我的直觉告诉我这里遗漏了一些东西。

编辑 1: 在@Wiktor Stribiżew 评论之后。 他指出(点击他的链接):

import re
print(re.sub(r'(.)(.)(.)(.)(.)(.)', 'a\6b', '123456'))
print(re.sub(r'(.)(.)(.)(.)(.)(.)', r'a\6b', '123456'))
# in my example the substitutions were not the same and the result were equal
# here indeed r' changes the results

给出:

ab
a6b

这让我更加困惑。

注意: 我读了 this stack overflow question about raw strings 这是 super 完整的。尽管如此,它并没有谈到替代

最佳答案

首先,

replacement patterns ≠ regular expression patterns

我们使用正则表达式模式来搜索匹配项,我们使用替换模式来替换使用正则表达式找到的匹配项。

注意:替换模式中唯一的特殊字符是反斜杠\。只有反斜杠必须加倍。

Python 中的替换模式语法

re.sub docs令人困惑,因为他们提到了可用于替换模式的字符串转义序列(如 \n\r)和正则表达式转义序列(\6) 和那些可以同时用作正则表达式和字符串转义序列的 (\&)。

我正在使用术语正则表达式转义序列 来表示由文字反斜杠 + 字符组成的转义序列,即 '\\X'r'\X' 和一个 字符串转义序列 来表示 \ 的序列和一个字符或一些序列,它们一起构成一个有效的 string escape sequence .它们仅在 regular string literals 中被识别.在原始字符串文字中,您只能转义 "(这就是为什么您不能以 \" 结束原始字符串文字的原因,但反弹仍然是部分然后是字符串)。

因此,在替换模式中,您可以使用反向引用:

re.sub(r'\D(\d)\D', r'\1', 'a1b')    # => 1
re.sub(r'\D(\d)\D', '\\1', 'a1b')    # => 1
re.sub(r'\D(\d)\D', '\g<1>', 'a1b')  # => 1
re.sub(r'\D(\d)\D', r'\g<1>', 'a1b') # => 1

您可能会看到 r'\1''\\1' 是相同的替换模式,\1。如果您使用 '\1',它将被解析为一个字符串转义序列,一个具有八进制值 001 的字符。如果您忘记将 r 前缀与明确的反向引用一起使用,也没有问题,因为 \g 不是有效的字符串转义序列,并且 \ 转义字符保留在字符串中。阅读我链接到的文档:

Unlike Standard C, all unrecognized escape sequences are left in the string unchanged, i.e., the backslash is left in the result.

因此,当您将 '\.' 作为替换字符串传递时,您实际上发送了 \. 两个字符的组合作为替换字符串,这就是为什么您在结果中得到 \.

\是Python替换模式中的一个特殊字符

如果你使用 re.sub(r'\s+\.', r'\\.', text),你会得到与 text2 相同的结果> 和 text3 案例,参见 this demo .

发生这种情况是因为 \\,两个文字反斜杠,表示替换模式中的单个反斜杠。如果您的正则表达式模式中没有第 2 组,但在替换中传递 r'\2' 以实际替换为 \2 字符组合,你会得到一个错误。

因此,当您拥有动态的、用户定义的替换模式时,您需要将替换模式中的所有反斜杠加倍,这些反斜杠将作为文字字符串传递:

re.sub(some_regex, some_replacement.replace('\\', '\\\\'), input_string)

关于Python Regex 转义运算符\in 替换和原始字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56523535/

相关文章:

Python 监视文件夹 - 询问文件大小列表

python - 密文 Letter Freq Substitution : Comparing 2 dictionaries' dict keys by value and altering a text

regex - 我编写了一个正则表达式来将子字符串与其周围的空格匹配,但这效果不佳

python - findContours返回具有重复点的轮廓

python - TensorBoard --logdir ="path/to/log"(无法分配给运算符(operator))

python - 如果 pandas merge 找到多个匹配项,则将值行写入一个字段

regex - 如何在R中的单词之间替换特殊字符

r - 在大型数据集上优化 sapply-grepl

regex - 匹配帐号的正则表达式

Javascript 正则表达式用于包含数字的字符串