我尝试了不同的想法,但还没有成功。所以这篇文章。
一些背景:我正试图破译一个Makefile,它可能包括来自一个单独的文件变量。我已经成功地读取了Makefile中的所有变量,并成功地将其包含到python字典中。但是现在我发现每个值实际上都引用了字典中的其他变量。我想做的是展开字典中的所有值,使其具有独立于其他键/值对的文本。这肯定涉及到递归(恕我直言),但我非常有兴趣听到任何其他建议。
注意并不是所有的变量都有关联的值。在本例中,将键替换为NULL字符串。
现在用一些代码来演示上面所说的:
让键、值对的列表为
*A = -L${F} ${B} ${D},
*B = -L/myhome,
*F =/usr/lib
我想写一个python脚本(可能使用regex)递归地替换匹配'${XXX}'的值与相应的键,直到没有更多的值与规定的模式匹配(即,一切都展开)。由于D没有与之关联的值,因此我希望a的值最终为(例如)
*A = -L/usr/lib -L/myhome
提前感谢。
利用re.subn
,它返回替换次数(因此您知道何时停止)并接受repl
参数的函数(从vars字典中选择值):
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},上面的程序将永远不会结束。
使用辅助函数进行递归展开,您可以使用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'}
像这样:
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)
小心无限替换循环!