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

max*_*max 5 python regex python-3.x

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

我怎样才能做到这一点?

Qta*_*tax 6

上一个使用的答案re.escape()会逃避太多,你会在替换和替换的字符串中得到不合需要的反斜杠.

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

replacement = replacement.replace("\\", "\\\\")
Run Code Online (Sandbox Code Playgroud)

示例:

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("\\", "\\\\"), "###")
Run Code Online (Sandbox Code Playgroud)

输出:

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 \\
Run Code Online (Sandbox Code Playgroud)


ste*_*ema 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]
Run Code Online (Sandbox Code Playgroud)

正在印刷

A
B
['A', '\x01', '\n', 'B']
['0x41', '0x1', '0xa', '0x42']
Run Code Online (Sandbox Code Playgroud)

因此,当我键入\并1在代码中,s不包含这两个字符时,它包含ASCII字符0x01,即"标题的开头".同样的\n,它转换为0x0aLinefeed角色.

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

s = r"A\1\nB"
print s
print [x for x in s]
print [hex(ord(x)) for x in s]
Run Code Online (Sandbox Code Playgroud)

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

A\1\nB
['A', '\\', '1', '\\', 'n', 'B']
['0x41', '0x5c', '0x31', '0x5c', '0x6e', '0x42']
Run Code Online (Sandbox Code Playgroud)

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

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

可能存在这样的情况:应该将字符串传递给正则表达式,因此在正则表达式中具有特殊含义的每个字符(例如+*$ [.)都需要转义,因此有一个特殊的函数re.escape可以执行这个工作.

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

所以新情况:

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

s = r"A\1\nB"
print re.sub(r"(Replace)" ,s , "1 Replace 2")
Run Code Online (Sandbox Code Playgroud)

结果是

1 AReplace
B 2
Run Code Online (Sandbox Code Playgroud)

该\1已被替换的捕获组的内容和\n与该换行字符.

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

  1. 创建者不确定字符串行为,如果他输入\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
    
    Run Code Online (Sandbox Code Playgroud)

    输出:

    1 A\1
    B 2
    ['1', ' ', 'A', '\\', '1', '\n', 'B', ' ', '2']
    ['0x31', '0x20', '0x41', '0x5c', '0x31', '0xa', '0x42', '0x20', '0x32']
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创作者确切地知道他在做什么,如果他想要换行,他就会输入\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]
    
    Run Code Online (Sandbox Code Playgroud)

    输出:

    1 A\1\nB 2
    ['1', ' ', 'A', '\\', '1', '\\', 'n', 'B', ' ', '2']
    ['0x31', '0x20', '0x41', '0x5c', '0x31', '0x5c', '0x6e', '0x42', '0x20', '0x32']
    
    Run Code Online (Sandbox Code Playgroud)