使用递归来识别有效的正则表达式

时间:2014-03-22 23:34:26

标签: python regex recursion

我一直在开发一个程序,其函数采用如下字符串:((1.(0.2)2).0)并返回True(如果它是正则表达式)。到目前为止,这里是mmy代码:

def is_regex(s):
    #Takes a string 's' and produces True if it is a valid regular expression
    #But False otherwise
    ex = '( + 3* + | + 6* + )'
    leaves = ['1', '2', '0', '1*', '2*', '0*']
    internal_nodes = ['|', '.']
    stripped_string = s.strip('()')

    if len(s.strip('()')) == 1:
        if '0' in s.strip('()') or '1' in s.strip('()') or '2' in s.strip('()')  or 'e' in s.strip('()'):
        return True
    elif len(s.strip('()')) == 0:
        return True
    elif stripped_string in leaves[3:6]:
        return True 
    elif len(stripped_string) == 3:
        if stripped_string[0] in leaves and stripped_string[2] in leaves:
            if stripped_string[1] in internal_nodes:
                return True 
    elif '.' in s and len(stripped_string) > 3:
        dot_position = s.rfind('.')
        if s.rfind('.') > s.rfind(')', 0, len(s)-1): #if '.' is only surrounded by one set of () then it is the root of the tree
            is_regex(s[dot_position +1])

这里的想法是我想找到树的根,并检查它的两个孩子是否是有效的正则表达式,如果它们是我移动一个递归,直到我在叶子上,如果它通过所有测试,直到它击中叶子,然后整个正则表达式True

对于我在那里的最后一行is_regex(s[dot_position +1])我没有得到任何返回,即使我知道s[dot_position +1]返回0所以应该没有问题。在这一行中,我要检查.的正确孩子0

编辑:另一个问题:我需要测试左孩子是否也是真的。我该怎么做?我不需要将两者都传递给is_regex吗?或者我应该检查左右两侧是否都是真的然后继续?这令人困惑

1 个答案:

答案 0 :(得分:1)

这可能是现存最常见的递归错误。如果你没有return递归调用的结果,Python 不会为你返回它 - 它会像往常一样继续运行该函数。由于之后没有别的东西,它会在没有返回的情况下掉线 - 而Python的规则意味着它将隐含return Noneis_regex(s[dot_position + 1])的结果是忽略,除非您明确地返回它(或以其他方式使用它)。


通过此功能,您在其他两条路径中遇到类似的错误:

if len(s.strip('()')) == 1:
    if '0' in s.strip('()') or '1' in s.strip('()') or '2' in s.strip('()')  or 'e' in s.strip('()'):
    return True

elif len(stripped_string) == 3:
    if stripped_string[0] in leaves and stripped_string[2] in leaves:
        if stripped_string[1] in internal_nodes:
            return True 

在这两种情况下,如果外部if触发但内部ifs失败,则最终返回None。这不是一个严重的问题,因为None在调用代码if is_regex(not_a_regex)时仍然会测试错误 - 但为了保持一致性并明确处理这些情况(而不是基本上忘记它们并拥有它< em>发生工作),你可能想要返回False。最简单的方法是返回布尔表达式而不是测试它们:

if len(s.strip('()')) == 1:
    return '0' in s.strip('()') or '1' in s.strip('()') or '2' in s.strip('()')  or 'e' in s.strip('()')

elif len(stripped_string) == 3:
    return stripped_string[0] in leaves and stripped_string[2] in leaves and stripped_string[1] in internal_nodes

为了测试左边的孩子,你确实必须递归到 - 单独,介意(将它们传递给相同的递归调用可能是可行的,但不太可能有效)。我会这样做:

dot_position = s.rfind('.')
if s.rfind('.') > s.rfind(')', 0, len(s)-1): #if '.' is only surrounded by one set of () then it is the root of the tree
    left_child =  s[dot_position - 1]
    right child = s[dot_position + 1]
    return is_regex(left_child) and is_regex(right_child)

这是涉及树结构的任何算法中非常常见的模式:测试当前节点中的值,然后依次递归调用每个子节点上的相同例程来测试所有子树;返回依赖于所有递归调用的结果的结果。维基百科称之为'depth-first pre-order walk'