【问题标题】:Python Updating a regex dictionary using the previous expression/key?Python 使用以前的表达式/键更新正则表达式字典?
【发布时间】:2021-12-04 03:24:09
【问题描述】:

我有这个函数可以用它的正则表达式替换字典值中的命名规则,比如#digit#:[0-9)

例如,调用这个函数:

def expand_re(pat_dict:{str:str}):
    pat_list = list(pat_dict.items())
    for key, rule in pat_dict.items():
        expression = re.compile(r'#\w+#')
        pat_dict[key] = re.sub(expression, f"(?:{pat_list[0][1]})", rule)
    return pat_dict

在这本词典上: pd = dict(digit = r'[0-9]', integer = r'[+-]?#digit##digit#*') 会产生: {'digit': '[0-9]', 'integer': '[+-]?(?:[0-9])(?:[0-9])*'}

而且它工作得很好。但是,如果字典开始使用前一个值的命名规则,它就不起作用。所以在字典上调用 expand_re:

pd = dict(a='correct',b='#a#',c='#b#',d='#c#',e='#d#',f='#e#',g='#f#')

我的函数产生:

{'a': 'correct',
 'b': '(?:correct)',
 'c': '(?:correct)',
 'd': '(?:correct)',
 'e': '(?:correct)',
 'f': '(?:correct)',
 'g': '(?:correct)'
}

当我希望它产生时:

{'a': 'correct',
 'b': '(?:correct)',
 'c': '(?:(?:correct))',
 'd': '(?:(?:(?:correct)))',
 'e': '(?:(?:(?:(?:correct))))',
 'f': '(?:(?:(?:(?:(?:correct)))))',
 'g': '(?:(?:(?:(?:(?:(?:correct))))))'
}

我怎么能做到这一点?我尝试使用字典的 .update() 方法,但无济于事。

【问题讨论】:

    标签: python regex dictionary


    【解决方案1】:

    这是您的代码的修复程序,可按您的需要工作。请注意,虽然逻辑是相同的,但存在键被替换顺序的缺陷。这意味着如果键被洗牌,它不会做你想做的事。

    import re
    def expand_re(pat_dict:{str:str}): 
        expression = re.compile(r'#(\w+)#')
        for key in pat_dict:
            pat_dict[key] = re.sub(expression, lambda x: f"(?:{pat_dict[x.group(1)]})", pat_dict[key])
        return pat_dict
    
    d = dict(a='correct',b='#a#',c='#b#',d='#c#',e='#d#',f='#e#',g='#f#')
    
    expand_re(d)
    

    输出:

    {'a': 'correct',
     'b': '(?:correct)',
     'c': '(?:(?:correct))',
     'd': '(?:(?:(?:correct)))',
     'e': '(?:(?:(?:(?:correct))))',
     'f': '(?:(?:(?:(?:(?:correct)))))',
     'g': '(?:(?:(?:(?:(?:(?:correct))))))'}
    

    展示逻辑中(潜在)缺陷的示例

    >>> expand_re(dict(a='correct',b='#a#',c='#b#',e='#d#',d='#c#',f='#e#',g='#f#'))
    {'a': 'correct',
     'b': '(?:correct)',
     'c': '(?:(?:correct))',
     'e': '(?:#c#)',
     'd': '(?:(?:(?:correct)))',
     'f': '(?:(?:#c#))',
     'g': '(?:(?:(?:#c#)))'}
    

    没有正则表达式的版本

    def expand_re(pat_dict:{str:str}): 
        for key, value in pat_dict.items():
            if value.startswith('#') and value.endswith('#') and value[1:-1] in pat_dict:
                pat_dict[key] = f'(?:{pat_dict[value[1:-1]]}'
        return pat_dict
    

    【讨论】:

    • 啊,我明白了。我真的应该养成更多地考虑和使用 lambdas 的习惯。即使解决方案在 dict 变得无序时会中断,但是,非常感谢您的帮助!
    • 此外,如果您想要做的事情并不比这里描述的替换更复杂,您不需要正则表达式(也不需要 lambda)。您只需将'(?:'')' 连接到匹配键
    • 注明。这确实简单了很多。我试图练习使用 re 方法,但这可能会使任务过于复杂。
    • 以我的更新为例(仍然是相同的缺陷)。如果您有兴趣修复该缺陷,您可能应该使用递归。如果您尝试一下并希望得到反馈,请不要犹豫,提出一个新问题并在此处放置链接。
    • 我在考虑使用递归,但不确定。感谢您指出了这一点!我会继续尝试一下。再次,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2014-10-14
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    • 2013-08-13
    • 2016-01-25
    • 1970-01-01
    • 2016-06-01
    相关资源
    最近更新 更多