Pyparsing:将infixnotation与setResultsName

时间:2017-11-08 16:21:15

标签: python parsing pyparsing

我正在尝试使用infixNotation(之前为operatorPrecedence)编写语法,但我无法弄清楚如何使用setResultsName

我尝试这样做的原因是我在searchparser之上为布尔搜索查询构建了一个语法,但是对于很长的表达式它会运行RecursionError: maximum recursion depth exceeded in comparison

所以看起来通过使用infixNotation(searchparser没有),我可以避免遇到这个错误。 所以我试图将语法调整为infixNotation,但我的评估在很大程度上依赖于在结构化解析结果中包含每个运算符的名称,特别是可以轻松访问运算符的参数。

我开始从pyparsing book中给出的例子开始:

and_ = CaselessLiteral("and")
or_  = CaselessLiteral("or")
not_ = CaselessLiteral("not")
searchTerm = Word(alphanums) | quotedString.setParseAction( removeQuotes )
searchExpr = infixNotation( searchTerm,
      [
      (not_, 1, opAssoc.RIGHT),
      (and_, 2, opAssoc.LEFT),
      (or_, 2, opAssoc.LEFT),
      ])

那么,如何在这里设置ParseResultName?

如果我尝试将其设置为操作员:

or_ = CaselessLiteral("or").setResultsName("OR")

此字符串的结果parseResult(' term1 OR term2 OR term3' )将如下所示:

<ITEM>
  <word>
    <word>
      <ITEM>term1</ITEM>
    </word>
    <OR>or</OR>
    <word>
      <ITEM>term2</ITEM>
    </word>
    <OR>or</OR>
    <word>
      <ITEM>term3</ITEM>
    </word>
  </word>
</ITEM>

这意味着所有术语和运算符都处于同一级别,而我想要这样的术语,其中术语被安排为运算符的参数:

<OR>
  <OR>
    <word>
      <ITEM>term1</ITEM>
    </word>
    <OR>
      <word>
        <ITEM>term2</ITEM>
      </word>
      <word>
        <ITEM>term3</ITEM>
      </word>
    </OR>
  </OR>
</OR>

我曾经在我以前的语法中用这样的东西来实现这个目的:

operatorOr << (Group(
            operatorAnd + Suppress(Keyword("OR", caseless=True)) + operatorOr
        ).setResultsName("OR") | operatorAnd)

但我无法弄清楚如何将结果名称设置为由运算符及其两个参数组成的组?

1 个答案:

答案 0 :(得分:0)

我建议您考虑使用类作为解析操作,以构建操作节点树,而不是使用结果名称。

在下面的代码中,我将UnOp和BinOp类附加到每个infixNotation运算符级别,该类别返回正确分配了operatoroperands属性的类的实例:

class OpNode:
    def __repr__(self):
        return "{}({}):{!r}".format(self.__class__.__name__,
                                    self.operator, self.operands)
class UnOp(OpNode):
    def __init__(self, tokens):
        self.operator = tokens[0][0]
        self.operands = [tokens[0][1]]

class BinOp(OpNode):
    def __init__(self, tokens):
        self.operator = tokens[0][1]
        self.operands = tokens[0][::2]

and_ = CaselessLiteral("and")
or_  = CaselessLiteral("or")
not_ = CaselessLiteral("not")
searchTerm = Word(alphanums) | quotedString.setParseAction(removeQuotes)
searchExpr = infixNotation(searchTerm,
      [
      (not_, 1, opAssoc.RIGHT, UnOp),
      (and_, 2, opAssoc.LEFT, BinOp),
      (or_, 2, opAssoc.LEFT, BinOp),
      ])

以下是一个示例字符串,显示了如何返回这些节点:

test = "term1 or term2 or term3 and term4 and not term5"
print(searchExpr.parseString(test))

给出:

[BinOp(or):['term1', 'term2', BinOp(and):['term3', 'term4', UnOp(not):['term5']]]]

您可以导航此已解析的树,并根据节点类型和运算符评估不同的节点。

同样asXML()不是转储解析数据的最佳工具,最好使用dump()方法。