Python re.sub:忽略替换字符串中的反向引用

时间:2011-12-09 06:43:08

标签: python regex python-3.x

我想用字符串替换模式。字符串以变量形式给出。它当然可能包含'\ 1',它不应该被解释为反向引用 - 而只是作为\ 1。

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:6)

使用re.escape()的上一个答案会逃避太多,并且在替换和替换的字符串中会出现不需要的反斜杠。

似乎在Python中只有反斜杠需要在替换字符串中转义,因此这样的事情就足够了:

replacement = replacement.replace("\\", "\\\\")

Example

import re

x = r'hai! \1 <ops> $1 \' \x \\'
print "want to see: "
print x

print "getting: "
print re.sub(".(.).", x, "###")
print "over escaped: "
print re.sub(".(.).", re.escape(x), "###")
print "could work: "
print re.sub(".(.).", x.replace("\\", "\\\\"), "###")

输出:

want to see: 
hai! \1 <ops> $1 \' \x \\
getting: 
hai! # <ops> $1 \' \x \
over escaped: 
hai\!\ \1\ \<ops\>\ \$1\ \\'\ \x\ \\
could work: 
hai! \1 <ops> $1 \' \x \\

答案 1 :(得分:5)

由于评论,我想了很久,并试了一下。帮助我增加了对逃避的理解,所以我几乎完全改变了我的答案,它可能对以后的读者有用。

NullUserException为您提供了简短的版本,我尝试再解释一下。感谢Qtax和Duncan的批评性评论,希望这个答案现在正确且有用。

反斜杠具有特殊含义,它是字符串中的转义字符,这意味着反斜杠和后续字符形成一个转义序列,当使用字符串完成某些操作时,转义为其他内容。这个“完成的东西”已经是字符串的创建。因此,如果你想在字面上使用\,你需要逃避它。这个转义字符就是反斜杠本身。

首先要开始一些例子,以便更好地了解会发生什么。我还在字符串中打印字符的ASCII码,以期增加对所发生情况的理解。

s = "A\1\nB"
print s
print [x for x in s]
print [hex(ord(x)) for x in s]

正在打印

A
B
['A', '\x01', '\n', 'B']
['0x41', '0x1', '0xa', '0x42']

因此,当我在代码中输入\1时,s不包含这两个字符,它包含ASCII字符0x01,即“标题的开头” ”。与\n相同,它将换算为0x0a换行符。

由于并不总是需要这种行为,因此可以使用原始字符串,忽略转义序列。

s = r"A\1\nB"
print s
print [x for x in s]
print [hex(ord(x)) for x in s]

我刚刚在字符串前添加了r,结果现在是

A\1\nB
['A', '\\', '1', '\\', 'n', 'B']
['0x41', '0x5c', '0x31', '0x5c', '0x6e', '0x42']

所有字符都是在我输入时打印的。

这就是我们的情况。现在还有下一件事。

可能存在一个字符串应该传递给正则表达式的字面意思,因此每个在正则表达式中具有特殊含义的字符(例如+ * $ [。)都需要转义,因此有一个特殊的执行此任务的函数re.escape

但是对于这个问题,这是一个错误的函数,因为字符串不应该在正则表达式中使用,而应该作为re.sub的替换字符串。

所以新情况:

包含转义序列的原始字符串应该用作re.sub的替换字符串。 re.sub也会处理转义序列,但与之前的处理有一个小但重要的区别:\n仍然会转换为0x0a换行符,但转换为{{ 1}}现在已经改变了!它将被\1中正则表达式的捕获组1的内容替换。

re.sub

结果是

s = r"A\1\nB"
print re.sub(r"(Replace)" ,s , "1 Replace 2")

1 AReplace B 2 已替换为捕获组的内容,\1替换为LineFeed字符。

重要的是,你必须了解这种行为,现在你有两种可能性(我不会判断哪一种是正确的)

  1. 创作者不确定字符串行为,如果他输入\n,那么他想要一个换行符。在这种情况下,使用它来转义后跟数字的\n

    \

    输出:

    OnlyDigits = re.sub(r"(Replace)" ,re.sub(r"(\\)(?=\d)", r"\\\\", s) , "1 Replace 2")
    print OnlyDigits
    print [x for x in OnlyDigits]
    print [hex(ord(x)) for x in OnlyDigits
    
  2. 创作者确切地知道他在做什么,如果他想要换行,他就会输入1 A\1 B 2 ['1', ' ', 'A', '\\', '1', '\n', 'B', ' ', '2'] ['0x31', '0x20', '0x41', '0x5c', '0x31', '0xa', '0x42', '0x20', '0x32'] 。在这种情况下逃避所有

    \0xa

    输出:

    All = re.sub(r"(Replace)" ,re.sub(r"(\\)", r"\\\\", s) , "1 Replace 2")
    print All
    print [x for x in All]
    print [hex(ord(x)) for x in All]