2017-02-10 78 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,您将收到错误消息,如果您的语法不解析整个字符串。从那里出发!