我想使用多个正则表达式对字符串进行多次替换。我还希望在单个过程中进行替换,以避免创建字符串的多个实例
让我们假设我要进行以下替换,同时避免多次使用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)"
)
编辑:如果有人看到Jonny的解决方案使用尽可能接近我的原始版本的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"
您可以通过将密钥保持为预期匹配并将replace和regex存储在嵌套的
dict
中来实现这一点。鉴于您希望匹配特定的字符,此定义应该有效如果没有要使用的表达式与空字符串匹配(如果要替换,这是一个有效的假设),则可以在
|
使用表达式之前使用组,然后检查找到匹配项的组:(exp1)|(exp2)|(exp3)
或者命名组,这样就不必计算子表达式中的子组
替换功能可以查看哪个组匹配,并从列表中选择替换
我提出了这个实现:
打印
local fowls drink cocoa
相关问题 更多 >
编程相关推荐