2017-02-10 84 views
2

我有以下的語法和測試案例:pyparsing不解析整個字符串

from pyparsing import Word, nums, Forward, Suppress, OneOrMore, Group 

#A grammar for a simple class of regular expressions 
number = Word(nums)('number') 
lparen = Suppress('(') 
rparen = Suppress(')') 

expression = Forward()('expression') 

concatenation = Group(expression + expression) 
concatenation.setResultsName('concatenation') 

disjunction = Group(lparen + OneOrMore(expression + Suppress('|')) + expression + rparen) 
disjunction.setResultsName('disjunction') 

kleene = Group(lparen + expression + rparen + '*') 
kleene.setResultsName('kleene') 

expression << (number | disjunction | kleene | concatenation) 

#Test a simple input 
tests = """ 
(8)*((3|2)|2) 
""".splitlines()[1:] 

for t in tests: 
    print t 
    print expression.parseString(t) 
    print 

結果應該是

[['8', '*'],[['3', '2'], '2']] 

,而是,我只得到

[['8', '*']] 

如何我是否使用pyparsing來解析整個字符串?

回答

1

concatenation您的concatenation表達式沒有做到您想要的,並且接近於左遞歸(幸運的是它是表達式中的最後一項)。你的語法工作,如果你不是做:

expression << OneOrMore(number | disjunction | kleene) 

隨着這一變化,我得到這樣的結果:

[['8', '*'], [['3', '2'], '2']] 

編輯: 你一個也避免<<的優先|如果您使用<<=操作相反:

expression <<= OneOrMore(number | disjunction | kleene) 
+0

謝謝!爲什麼在寫出連接的定義時不工作,這是否工作? –

+0

由於您的原始表達式與'kleene'匹配,並且原始'expression'定義中的任何內容都沒有說明要繼續解析。當你將'concatenation'作爲'expression'的一部分包含進來時,它會傳達出這個想法,但是會讓你掉落左邊的遞歸兔子洞。或者,如果你用'^'運算符替換了你的'|'運算符(給出一個「最長匹配」或者表達式而不是MatchFirst),那麼你也可以進行連接評估 - 但是,你也可以通過嘗試通過評估一個「表達式」評估一個「表達式」。 – PaulMcG

+0

您使用的是什麼版本的pyparsing?當前版本包含一些有用的方法,特別是'expression.runTests',它將採用多行測試輸入並針對每行運行表達式並打印解析結果或診斷輸出。在你的例子中,你可以用'expression.runTests(tests)'來替換你的for循環。事實是,多年來,我已經寫了完全相同的循環大約一千次,並且終於明白了對錶達式的輔助方法是有用的。 – PaulMcG

2

parseString有一個參數parseAll。如果您撥打parseStringparseAll=True,您將收到錯誤消息,如果您的語法不解析整個字符串。從那裏出發!