Python与正则表达式递归替换字符串

时间:2011-08-17 04:20:38

标签: python regex recursion

我为此尝试了不同的想法但尚未成功。因此这篇文章。

一些背景:我正在尝试破译可能包含来自单独文件的变量的Makefile。我已经设法读取Makefile中的所有变量,并且还成功地将其包含到python词典中。但现在我发现每个值基本上都引用了作为字典一部分的其他变量。我想要做的是展开字典中的所有值,使其具有独立于其他键/值对的文本。这肯定涉及递归(恕我直言),但我非常有兴趣听取任何其他建议。

请注意,并非所有变量都可能具有与之关联的值。在这种情况下,请使用NULL字符串替换密钥。

现在有些代码可以演示上面说的内容:

让键,值对的列表为

* A = -L $ {F} $ {B} $ {D},

* B = -L / myhome,

* F = / usr / lib

我想写一个python脚本(可能带有正则表达式)以递归方式将匹配'$ {XXX}'的值替换为相应的键,直到没有更多可用的值与指定的模式匹配(即,所有内容都展开) 。由于D没有与之关联的值,我希望A的值最终为(例如)

* A = -L / usr / lib -L ​​/ myhome

提前致谢。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:4)

利用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},请注意上述程序永远不会结束。你没有具体说明在这种情况下会发生什么。

答案 1 :(得分: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'}

答案 2 :(得分: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)

注意无限的替换循环!