Python正则替换 - 在替换中使用匹配作为字典键
我正在把一个程序从Perl语言转到Python(3.3)。我对Python还比较陌生。在Perl中,我可以做一些很巧妙的正则表达式替换,比如:
$string =~ s/<(\w+)>/$params->{$1}/g;
这个代码会在$params
这个哈希表中的值进行替换,使用正则表达式匹配到的内容作为哈希表的键。
那么在Python中,有什么好的(符合Python风格的)方法可以简洁地实现这个功能呢?我想出了类似这样的代码:
string = re.sub(r'<(\w+)>', (what here?), string)
如果我能传递一个函数,把正则表达式匹配的结果映射到一个字典中,那会很好。这样做可以吗?
谢谢你的帮助。
1 个回答
17
你可以给 re.sub
传一个可调用的对象,这样它就知道该如何处理匹配到的内容。
s = re.sub(r'<(\w+)>', lambda m: replacement_dict.get(m.group()), s)
使用 dict.get
可以让你提供一个“备用方案”,也就是说,如果你要替换的单词不在替换字典里,就会使用这个备用方案。
lambda m: replacement_dict.get(m.group(), m.group())
# fallback to just leaving the word there if we don't have a replacement
我想提一下,当使用 re.sub
(还有 re.split
等相关函数)时,如果你想指定一些在你想替换的内容周围的东西,通常使用“前后查找”表达式会更简洁,这样就不会把匹配内容周围的东西也替换掉。因此在这种情况下,我会这样写你的正则表达式:
r'(?<=<)(\w+)(?=>)'
否则你就得在你的 lambda
里处理一下括号的切割和再拼接。为了让你更清楚我在说什么,给你一个例子:
s = "<sometag>this is stuff<othertag>this is other stuff<closetag>"
d = {'othertag': 'blah'}
#this doesn't work because `group` returns the whole match, including non-groups
re.sub(r'<(\w+)>', lambda m: d.get(m.group(), m.group()), s)
Out[23]: '<sometag>this is stuff<othertag>this is other stuff<closetag>'
#this output isn't exactly ideal...
re.sub(r'<(\w+)>', lambda m: d.get(m.group(1), m.group(1)), s)
Out[24]: 'sometagthis is stuffblahthis is other stuffclosetag'
#this works, but is ugly and hard to maintain
re.sub(r'<(\w+)>', lambda m: '<{}>'.format(d.get(m.group(1), m.group(1))), s)
Out[26]: '<sometag>this is stuff<blah>this is other stuff<closetag>'
#lookbehind/lookahead makes this nicer.
re.sub(r'(?<=<)(\w+)(?=>)', lambda m: d.get(m.group(), m.group()), s)
Out[27]: '<sometag>this is stuff<blah>this is other stuff<closetag>'