如何在Python中使用匹配组和变量进行替换

13 投票
4 回答
18685 浏览
提问于 2025-04-16 13:51

我刚开始学Python。这可能很简单,但我还没找到答案。

rndStr = "20101215"
rndStr2 = "20101216"
str = "Looking at dates between 20110316 and 20110317"
outstr = re.sub("(.+)([0-9]{8})(.+)([0-9]{8})",r'\1'+rndStr+r'\2'+rndStr2,str)

我想要的输出是:

Looking at dates between 20101215 and 20101216

但我得到的是:

P101215101216

这两个rndStr的值其实没什么关系。可以假设它们是随机的或者是用户输入的(我这里用静态值是为了简单起见)。谢谢大家的帮助。

4 个回答

-1
rndStr = "20101215"
rndStr2 = "20101216"
mys = "Looking at dates between {0} and {1}".format(rndStr, rndStr2)

请不要把 str 当作变量名使用;这样会覆盖掉 Python 里内置的 str 类型。

3

注意,如果你把 rndStrrndStr2 的值改成文本(比如 'abc'),而不是数字,你会得到更接近预期的结果吗?

在你给 re.sub 的表达式中,你有 r'\1'+rndStr+...。这会组合成 '\1'+'20101215',然后它试图引用 \120101215 的回溯引用,这可能不是你想要的结果……

你可以使用命名的回溯引用,这样可以让回溯引用更清晰:

rep1 = "20101215"
rep2 = "20101216"
st = "Looking at dates between 20110316 and 20110317"

print re.sub(r'(?P<fp>.+)[0-9]{8}(?P<lp>.+)[0-9]{8}',
            r'\g<fp>'+rep1+r'\g<lp>'+rep2,st)

更好的方法是使用更容易理解的语法,并检查匹配尝试的返回结果:

m=re.search(r'(?P<fp>.+)[0-9]{8}(?P<lp>.+)[0-9]{8}',st)
if m:
    print m.group('fp')+rep1+m.group('lp')+rep2  #you could use m.group(1) too
else:
    print "no match..."

无论哪种情况,你想要的字符串 Looking at dates between 20101215 and 20101216 都能生成。

关于命名回溯引用的 Python 文档:

(?P<name>...)

这和普通的括号类似,但 通过符号组名 'name',可以在 正则表达式的其他部分访问 该组匹配到的子字符串。组名必须是 有效的 Python 标识符,并且每个 组名在正则表达式中只能定义一次。 一个符号组也是一个编号组,就像 如果该组没有命名一样。因此,在下面的 示例中,名为 'id' 的组也可以被 作为编号组 1 引用。

例如,如果模式是 (?P<id>[a-zA-Z_]\w*),那么可以通过 组名在匹配对象的方法中引用该组, 比如 m.group('id')m.end('id'),同时 也可以在正则表达式本身中通过组名 引用(使用 (?P=id)),以及在 提供给 .sub() 的替换文本中 (使用 \g<id>)。

28

你的反向引用有点模糊。你的替换字符串变成了

\120101215\220101216

这两个数字都挺大的,反向引用起来有点麻烦 :)

要解决这个问题,可以使用这个语法:

r'\g<1>'+rndStr+r'\g<2>'+rndStr2 

另外,你的括号用得太多了(如果你像我一样说英式英语,可以叫它“括号”:) - 你不需要在 [0-9]{8} 的部分加括号,因为你并不打算反向引用这些部分:

re.sub("(.+)[0-9]{8}(.+)[0-9]{8}",...

这样就足够了。

(还有,像其他地方提到的,不要把 str 作为变量名。否则你会花很多时间去调试为什么 str.replace() 不再工作。虽然我从来没有遇到过这种情况...绝对没有。 :)

所以整个内容变成:

import re
rndStr = "20101215"
rndStr2 = "20101216"
s = "Looking at dates between 20110316 and 20110317"
outstr = re.sub("(.+)[0-9]{8}(.+)[0-9]{8}", r'\g<1>'+rndStr+r'\g<2>'+rndStr2, s) 
print outstr

生成:

Looking at dates between 20101215 and 20101216

撰写回答