Python用regex递归替换字符串



我尝试了不同的想法,但还没有成功。所以这篇文章。

一些背景:我正试图破译一个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)

小心无限替换循环!

最新更新