注意:operatorPrecedence
不推荐使用pyparsing方法,而推荐使用method name infixNotation
。
尝试更改:
expr = pp.operatorPrecedence(clause,[
("OR", 2, pp.opAssoc.LEFT, ),
("AND", 2, pp.opAssoc.LEFT, ),])
至:
expr = pp.operatorPrecedence(condition,[
("OR", 2, pp.opAssoc.LEFT, ),
("AND", 2, pp.opAssoc.LEFT, ),])
operatorPrecedence的第一个参数是要与运算符一起使用的原始操作数-无需在圆括号中包含您的complexExpr- operatorPrecedence会为您完成此操作。由于操作数实际上是另一个更深层次的比较,因此您可以考虑更改:
condition = (expr + operator + expr)
至:
condition = pp.Group(expr + operator + expr)
因此,operatorPrecedence的输出更易于处理。有了这些更改,解析x > 7 AND x < 8 OR x = 4
将给出:
[[['x', '>', '7'], 'AND', [['x', '<', '8'], 'OR', ['x', '=', '4']]]]
识别OR的较高优先级并首先对其进行分组。(您确定要使用AND和OR优先顺序吗?我认为传统顺序是相反的,如此Wikipedia条目所示。)
我想您也在问为什么pyparsing和operatorPrecedence不以嵌套二进制对的形式返回结果,也就是说,您希望解析“ A,B和C”将返回:
[['A', 'and', 'B'] 'and', 'C']
但是您得到的是:
['A', 'and', 'B', 'and', 'C']
这是因为operatorPrecedence使用重复而不是递归来解析相同优先级下的重复操作。请参阅与您的问题非常相似的问题,其答案包括解析动作,可将您的重复解析树转换为更传统的二进制解析树。您还可以在pyparsing Wiki页面上找到使用operatorPrecedence实现的示例布尔表达式解析器。
:澄清一下,这是我建议您将解析器减少为:
import pyparsing as pp
operator = pp.Regex(">=|<=|!=|>|<|=").setName("operator")
number = pp.Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?")
identifier = pp.Word(pp.alphas, pp.alphanums + "_")
comparison_term = identifier | number
condition = pp.Group(comparison_term + operator + comparison_term)
expr = pp.operatorPrecedence(condition,[
("AND", 2, pp.opAssoc.LEFT, ),
("OR", 2, pp.opAssoc.LEFT, ),
])
print expr.parseString("x > 7 AND x < 8 OR x = 4")
expr = pp.operatorPrecedence(condition,[
("NOT", 1, pp.opAssoc.RIGHT, ),
("AND", 2, pp.opAssoc.LEFT, ),
("OR", 2, pp.opAssoc.LEFT, ),
])
在某个时候,您可能想comparison_term
使用更完整的算术表达式来扩展的定义,并用其自己的operatorPrecedence
定义来定义。我建议这样做,而不是创建一个庞然大物的opPrec
定义,因为您已经提到了性能上的一些缺点opPrec
。如果仍然遇到性能问题,请查看ParserElement.enablePackrat
。