我想使用多个正则表达式对字符串进行多次替换。我还想在一次传递中进行替换,以避免创建字符串的多个实例。
假设对于参数,我想进行下面的替换,同时避免多次使用 re.sub(),无论是显式使用还是循环使用:
import re
text = "local foals drink cola"
text = re.sub("(?<=o)a", "w", text)
text = re.sub("l(?=a)", "co", text)
print(text) # "local fowls drink cocoa"
我找到的最接近的解决方案是从替换目标字典中编译正则表达式,然后使用 lambda 函数将每个匹配的目标替换为字典中的值。但是,这种方法在使用元字符时不起作用,因此删除了本示例中正则表达式所需的功能。
让我首先用一个无需元字符的示例来演示:
import re
text = "local foals drink cola"
subs_dict = {"a":"w", "l":"co"}
subs_regex = re.compile("|".join(subs_dict.keys()))
text = re.sub(subs_regex, lambda match: subs_dict[match.group(0)], text)
print(text) # "coocwco fowcos drink cocow"
现在观察将所需的元字符添加到字典键会导致 KeyError:
import re
text = "local foals drink cola"
subs_dict = {"(?<=o)a":"w", "l(?=a)":"co"}
subs_regex = re.compile("|".join(subs_dict.keys()))
text = re.sub(subs_regex, lambda match: subs_dict[match.group(0)], text)
>>> KeyError: "a"
原因是 sub() 函数正确地找到了表达式的匹配项"(?<=o)a"
,所以现在必须在字典中找到它以返回其替换,但是提交用于字典查找的值match.group(0)
是对应的匹配字符串"a"
。搜索也不起作用match.re
在字典中(即产生匹配的表达式),因为它的值是从字典键编译的整个不相交表达式(即"(?<=o)a|l(?=a)"
).
编辑:如果有人会受益于看到 thejonny 的解决方案使用 lambda 函数实现,尽可能接近我的原始版本,它会像这样工作:
import re
text = "local foals drink cola"
subs_dict = {"(?<=o)a":"w", "l(?=a)":"co"}
subs_regex = re.compile("|".join("("+key+")" for key in subs_dict))
group_index = 1
indexed_subs = {}
for target, sub in subs_dict.items():
indexed_subs[group_index] = sub
group_index += re.compile(target).groups + 1
text = re.sub(subs_regex, lambda match: indexed_subs[match.lastindex], text)
print(text) # "local fowls drink cocoa"