2010-11-26 48 views
11

顯然,這個問題出現了相當頻繁,讀解析在python嵌套的括號,按級別搶內容

Regular expression to detect semi-colon terminated C++ for & while loops

和思考一會兒這個問題後,我寫了一個函數返回所包含的內容內嵌任意數量的嵌套()

該函數可以很容易地擴展到任何正則表達式對象,在這裏發表您的想法和注意事項。

任何重構的建議,將不勝感激

(注意,我是新來的蟒蛇還在,並沒有覺得自己搞清楚如何引發異常或什麼的,所以我只是有函數返回「失敗」如果couldin't弄清楚發生了什麼事情)

編輯功能考慮到的意見:

def ParseNestedParen(string, level): 
    """ 
    Return string contained in nested(), indexing i = level 
    """ 
    CountLeft = len(re.findall("\(", string)) 
    CountRight = len(re.findall("\)", string)) 
    if CountLeft == CountRight: 
     LeftRightIndex = [x for x in zip(
     [Left.start()+1 for Left in re.finditer('\(', string)], 
     reversed([Right.start() for Right in re.finditer('\)', string)]))] 

    elif CountLeft > CountRight: 
     return ParseNestedParen(string + ')', level) 

    elif CountLeft < CountRight: 
     return ParseNestedParen('(' + string, level) 

    return string[LeftRightIndex[level][0]:LeftRightIndex[level][1]] 

回答

23

你不說清楚你的函數的規範是什麼,但這種行爲似乎是錯誤的我:

>>> ParseNestedParen('(a)(b)(c)', 0) 
['a)(b)(c'] 
>>> nested_paren.ParseNestedParen('(a)(b)(c)', 1) 
['b'] 
>>> nested_paren.ParseNestedParen('(a)(b)(c)', 2) 
[''] 

對您的代碼的其他評論:

  • Docstring說「生成」,但函數返回一個列表,而不是生成器。
  • 由於只返回一個字符串,爲什麼返回列表?
  • 在什麼情況下函數可以返回字符串fail
  • 反覆致電re.findall,然後扔掉結果是浪費。
  • 您嘗試重新平衡字符串中的括號,但您一次這樣做只有一個括號:
>>> ParseNestedParen(')' * 1000, 1) 
RuntimeError: maximum recursion depth exceeded while calling a Python object 

由於Thomi在question you linked to說,「正則表達式真的是錯誤的工具!「


通常的方法來解析嵌套表達式是使用堆棧,沿着這些線路:

def parenthetic_contents(string): 
    """Generate parenthesized contents in string as pairs (level, contents).""" 
    stack = [] 
    for i, c in enumerate(string): 
     if c == '(': 
      stack.append(i) 
     elif c == ')' and stack: 
      start = stack.pop() 
      yield (len(stack), string[start + 1: i]) 

>>> list(parenthetic_contents('(a(b(c)(d)e)(f)g)')) 
[(2, 'c'), (2, 'd'), (1, 'b(c)(d)e'), (1, 'f'), (0, 'a(b(c)(d)e)(f)g')] 
+0

與 相關的行爲ParseNestedParen('(a)(b)(c)',0) 實際上是正確的,但我的功能是工作的錯誤工具,我用 寫了函數string =「some_function another_function(some_argument))「 記住。 爲什麼返回列表?不應該有。好點,謝謝! 什麼時候我會返回失敗?我不知道。也許永遠不會它從那裏我編碼功能 repairedly調用查找所有是浪費?因此,我應該在[「\(」,「\)」]] 中使用列表 countparen = [re.findall(str)for str並使用它? 我該如何重新理解括號? 感謝您的意見! – 2010-11-26 12:18:40

0
#!/usr/bin/env python 
import re 

def ParseNestedParen(string, level): 
    """ 
    Generate strings contained in nested(), indexing i = level 
    """ 
    if len(re.findall("\(", string)) == len(re.findall("\)", string)): 
     LeftRightIndex = [x for x in zip(
     [Left.start()+1 for Left in re.finditer('\(', string)], 
     reversed([Right.start() for Right in re.finditer('\)', string)]))] 

    elif len(re.findall("\(", string)) > len(re.findall("\)", string)): 
     return ParseNestedParen(string + ')', level) 

    elif len(re.findall("\(", string)) < len(re.findall("\)", string)): 
     return ParseNestedParen('(' + string, level) 

    else: 
     return 'fail' 

    return [string[LeftRightIndex[level][0]:LeftRightIndex[level][1]]] 

測試:

if __name__ == '__main__': 

    teststring = "outer(first(second(third)second)first)outer" 

    print(ParseNestedParen(teststring, 0)) 
    print(ParseNestedParen(teststring, 1)) 
    print(ParseNestedParen(teststring, 2)) 

    teststring_2 = "outer(first(second(third)second)" 

    print(ParseNestedParen(teststring_2, 0)) 
    print(ParseNestedParen(teststring_2, 1)) 
    print(ParseNestedParen(teststring_2, 2)) 

    teststring_3 = "second(third)second)first)outer" 

    print(ParseNestedParen(teststring_3, 0)) 
    print(ParseNestedParen(teststring_3, 1)) 
    print(ParseNestedParen(teststring_3, 2)) 

輸出:

Running tool: python3.1 

['first(second(third)second)first'] 
['second(third)second'] 
['third'] 
['first(second(third)second)'] 
['second(third)second'] 
['third'] 
['(second(third)second)first'] 
['second(third)second'] 
['third'] 
>>> 
+0

所以,你可以告訴,該功能允許不平衡括號,雖然不是一個非常優雅的方式。 – 2010-11-26 11:54:28