使用正则表达式在Python中递归替换字符串
我试过不同的方法,但到现在为止都没有成功。所以我发了这个帖子。
先说一下背景:我正在尝试理解一个Makefile,这个文件可能会包含来自其他文件的变量。我已经成功地把Makefile里的所有变量和它的包含内容读进了一个Python字典里。但现在我发现每个值实际上都引用了字典里其他变量的值。我想做的是把字典里的所有值展开,变成不依赖于其他键/值对的文本。这肯定需要用到递归(我觉得),但我很想听听其他的建议。
需要注意的是,并不是所有的变量都有对应的值。如果没有值,就把这个键替换成一个空字符串。
接下来是一些代码来演示上面说的内容:
假设有一组键值对:
*A = -L${F} ${B} ${D},
*B = -L/myhome,
*F = /usr/lib
我想写一个Python脚本(可能会用到正则表达式),递归地把符合'${XXX}'格式的值替换成对应的键,直到没有更多符合这个格式的值为止(也就是说,所有的值都被展开了)。因为D没有对应的值,所以我希望A的值最终变成(例如):
*A = -L/usr/lib -L/myhome
提前感谢大家的帮助,任何建议都非常感谢。
3 个回答
0
像这样:
def unroll(stuff):
# Code to unroll.
# if something had been replaced:
replaced = True
# else
replaced = False
return stuff, replaced
def main():
stuff, replaced = unroll(stuff)
while replaced:
stuff, replaced = unroll(stuff)
不过要小心无限替换循环哦!
2
通过一个辅助函数来进行递归展开,你可以使用 re.sub
来替换每个值中所有不重叠的匹配项:
import re
RE_VAL = re.compile(r'\${(.*?)}')
def expand (val, src):
return RE_VAL.sub(lambda m: expand(src.get(m.group(1), ''), src), val)
def main ():
vals = {
'A': '-L${F} ${B} ${D}',
'B': '-L/myhome',
'D': '${E}',
'E': '${G}',
'F': '/usr/lib',
'G': '-O',
}
for k,v in vals.iteritems():
vals[k] = expand(v, vals)
print vals
# {'A': '-L/usr/lib -L/myhome -O', 'B': '-L/myhome', 'E': '-O', 'D': '-O', 'G': '-O', 'F': '/usr/lib'}
4
可以利用 re.subn
这个函数,它会返回替换的次数(这样你就知道什么时候可以停止了),而且它的 repl
参数可以接受一个函数,这样你就可以从变量字典中选择值。
import re
vs = {
'A' : '-L${F} ${B} ${D}',
'B' : '-L/myhome',
'F' : '/usr/lib',
}
while 1:
treps = 0
for k in vs:
ns, nreps = re.subn(r'''\${(\w+)}''', lambda match: vs.get(match.group(1), ''), vs[k])
if nreps: vs[k] = ns
treps += nreps
if not treps: break
print(vs)
# {'A': '-L/usr/lib -L/myhome ', 'B': '-L/myhome', 'F': '/usr/lib'}
要注意,上面的程序如果 A=${A},或者 A=${B} 而 B=${A} 的话,就永远不会结束。你没有说明在这种情况下应该怎么处理。