我一直在开发一个程序,其函数采用如下字符串:((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
吗?或者我应该检查左右两侧是否都是真的然后继续?这令人困惑
答案 0 :(得分:1)
这可能是现存最常见的递归错误。如果你没有return
递归调用的结果,Python 不会为你返回它 - 它会像往常一样继续运行该函数。由于之后没有别的东西,它会在没有返回的情况下掉线 - 而Python的规则意味着它将隐含return None
。 is_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'。