【问题标题】:Python with regex to replace strings recursivelyPython 用正则表达式递归替换字符串
【发布时间】:2011-10-28 14:38:43
【问题描述】:

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

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

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

现在用一些代码来演示上面所说的内容:

设一个键值对列表

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

*B = -L/我的家,

*F = /usr/lib

我想编写一个 python 脚本(可能使用正则表达式)以递归地用相应的键替换匹配 '${XXX}' 的值,直到没有更多可用的值匹配规定的模式(即,一切都展开) .由于 D 没有与之关联的值,我希望 A 的值最终是(例如)

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

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

【问题讨论】:

    标签: python regex recursion


    【解决方案1】:

    使用辅助函数进行递归扩展,您可以使用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'}
    

    【讨论】:

    • 非常好。这比我想象的要优雅得多。并生产我需要的东西。这里只是一个额外的问题:如果我有一个额外的字典作为参考,那么在用空字符串替换键之前,您是否可以实际检查参考中是否存在键(这就是现在发生的情况)。
    • 当然,只需将您的“默认”字典作为 arg 传递给 expand(),并将 src.get() 调用中的空字符串替换为对第二个字典的空安全调用。你最终得到:src.get(m.group(1), defaults.get(m.group(1), ''))
    【解决方案2】:

    利用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},上述程序将永远不会结束。您没有指定在这种情况下应该发生什么。

    【讨论】:

    • 这非常有效。即使对于未定义环境变量的退化情况:)我理解您的循环引用,但希望在我拥有的用例中,这永远不会发生。
    【解决方案3】:

    类似这样的:

    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)
    

    但要小心无限替换循环!

    【讨论】:

      猜你喜欢
      • 2022-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-13
      • 2018-07-13
      • 2015-11-30
      • 2021-11-29
      相关资源
      最近更新 更多