python - 使用 dump() 和 asXML() 函数时 pyparsing 不同的结果

标签 python parsing pyparsing

我在使用 pyparsing 解析结果时遇到问题。我有一个语法来解析一个表达式。在语法中的每个规则中都有 setResultName() 函数,因此我可以轻松地操作解析结果。但是当使用 dump() 函数查看结果的组织方式时,它不会显示所有解析的结果。但是,当使用 asXML() 函数时,所有结果都在那里并且按照我想要的方式构建。

语法如下:

# Rule for any alphanumeric word
identifier = Word(alphas, alphas + nums)

# Rule for "e" in floating point numbers
e = CaselessLiteral('E')

# Rule for booleans
boolean = (Keyword('True') 
           | Keyword('False')
).setParseAction(lambda tokens: bool(tokens[0])).setResultsName("boolean")

# Rule for integer numbers
integer = Word(nums).setParseAction(lambda tokens: int(tokens[0]))

# Rule for factor operator
factor_operator = (Literal('*') 
                   | Literal('/') 
                   | Literal('%')
).setResultsName("operator")

# Rule for term operator
term_operator = (Literal('+') 
                 | Literal('-')
).setResultsName("operator")

# Rule for double numbers
double = Combine(integer +
                 Optional(Literal('.') + Optional(integer)) +
                 Optional(e + Optional(term_operator) + integer)
).setParseAction(lambda tokens: float(tokens[0])).setResultsName("double")

# Forwarding expression rule
expression = Forward()

# Rule define type of factor
factor = Group((
          Literal('(').suppress() + 
              expression.setResultsName("expression") +
          Literal(')').suppress())
          | double 
          | boolean
).setResultsName("factor")

# Rule for factors
factors = Group(ZeroOrMore(factor_operator + factor)).setResultsName("factors")

# Rule for term
term = Forward()
term << Group(factor + delimitedList(factors)).setResultsName("term")

# Rule for terms
terms = Group(ZeroOrMore(term_operator + term)).setResultsName("terms")

# Rule for expression
expression << Group(Optional(term_operator) + term + delimitedList(terms)
).setResultsName("expression")

return expression

这是我要解析的表达式:

"(2 * 3) + 20 / 5 - 1"

这里是 dump() 的输出:

[[[[[[[2.0], ['*', [3.0]]], []]], []], ['+', [[20.0], ['/', [5.0]]], '-', [[1.0], []]]]]
- expression: [[[[[[2.0], ['*', [3.0]]], []]], []], ['+', [[20.0], ['/', [5.0]]], '-', [[1.0], []]]]
  - term: [[[[[2.0], ['*', [3.0]]], []]], []]
    - factor: [[[[2.0], ['*', [3.0]]], []]]
      - expression: [[[2.0], ['*', [3.0]]], []]
        - term: [[2.0], ['*', [3.0]]]
          - factor: [2.0]
            - double: 2.0
          - factors: ['*', [3.0]]
            - factor: [3.0]
              - double: 3.0
            - operator: *
        - terms: []
    - factors: []
  - terms: ['+', [[20.0], ['/', [5.0]]], '-', [[1.0], []]]
    - operator: -
    - term: [[1.0], []]
      - factor: [1.0]
        - double: 1.0
      - factors: []

以及 asXML() 的输出:

<expression>
  <expression>
    <term>
      <factor>
        <double>2.0</double>
      </factor>
      <factors>
        <operator>*</operator>
        <factor>
          <double>3.0</double>
        </factor>
      </factors>
    </term>
    <terms>
      <operator>-</operator>
      <term>
        <factor>
          <double>20.0</double>
        </factor>
        <factors>
          <operator>/</operator>
          <factor>
            <double>5.0</double>
          </factor>
        </factors>
      </term>
      <operator>+</operator>
      <term>
        <factor>
          <double>1.0</double>
        </factor>
        <factors>
        </factors>
      </term>
    </terms>
  </expression>
</expression>

问题出在带括号的嵌套表达式之后的术语标签上。在 xml 中,它显示其中的所有术语(即“+”、“20.0/5.0”、“-”、“1.0”),这应该是一个运算符和术语列表。使用 dump() 函数时,它仅显示最后一个运算符和术语(即“-”、“1.0”)。 谁能帮我理解这个?有什么我想念的吗?抱歉,我没有说清楚。

最佳答案

如果 dump()asXML() 之间存在差异,我更可能将其视为 asXML() 中的错误>。该方法被迫对需要的内容进行相当多的“猜测”,在某些情况下我很容易看出它猜错了。

pyparsing 的默认行为是将所有已解析的标记作为一个简单的字符串列表返回。无论解析器是如何构建的,它都会这样做。这是为了

(A + B + C).parseString

AA = A + B
(AA + C).parseString

and

DD = B + C
(A + DD).parseString

所有返回相同的东西。

让我们看一个简单的语法,名字/年龄对的倍数:

test = "Bob 10 Sue 12 Henry 7"

这是我们的解析器:

name = Word(alphas)
integer = Word(nums)

parser = OneOrMore(name + integer)

# or you can use the new multiplication syntax
parser = (name + integer) * (1,)

使用给定的示例文本和上述解析器,这将是:

['Bob', '10', 'Sue', '12', 'Henry', '7']

现在这并不难走完,一次阅读两个项目。但是,如果有额外的可选字段,那么事情就会变得更加棘手。因此,告诉 pyparsing 每个人的姓名和年龄应该分组在一起要容易得多。

parser = OneOrMore(Group(name + integer))

现在我们得到了每个人的子列表,并且无需猜测是否可能有其他选项。

[['Bob', '10'], ['Sue', '12'], ['Henry', '7']]

如果您将结果名称添加到原始未分组的解析器,我们会看到这一点(我使用的是"new"可调用语法,而不是冗长且令人分心的“setResultsName”调用格式):

parser = OneOrMore(name("name") + integer("age"))
result = parser.parseString(test)

了解我们现在对未分组结果的了解,如果我们要求 result.name,我们应该得到哪个名称?

如果您遇到多个表达式共享相同结果名称的情况,那么您有 3 个选项:

  • 只保留最后一个被解析(默认,这就是你所看到的)

  • 使用 Group 类添加分组,以便将多个共享结果分成不同的子结构

  • listAllItems=True 参数添加到 setResultsName()

    parser = (OneOrMore(name.setResultsName("name", listAllItems=True)
              + integer.setResultsName("age", listAllItems=True)))
    

    或者如果使用缩写的可调用格式,请在结果名称的末尾添加“*”:

    parser = OneOrMore(name("name*") + integer("age*"))
    

现在 result.name 将为您提供列表中所有已解析的名称,result.age 将为您提供相应的年龄。但对于这样的数据,我更愿意看到数据被解析成组。

parser = OneOrMore(Group(name("name") + integer("age")))

如果您希望 asXML() 使用标签“person”来标记每个组,然后将该名称添加到组中,并使用尾随的“*”来捕获所有组。

parser = OneOrMore(Group(name("name") + integer("age"))("person*")

(这已经是一个冗长的答案,所以我省略了这些测试的 dump() 和 asXML() 输出 - 留作 OP 和 future 读者的练习。)

关于python - 使用 dump() 和 asXML() 函数时 pyparsing 不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24982455/

相关文章:

python - 在 GAE 沙箱中运行 Python 的 nose 单元测试

c# - C# 或一般 .Net 中的 C 解析器

c - 解析和嵌套指针

python - pyparsing如何从字符串创建语法对象

python - 使用停止标记解析字符串

python - 如何在列表 C++ 中存储套接字

python - 如何从松弛的用户那里获取输入以进一步进行?

python - 在 html 中搜索颜色标签(Python 3)

java - 有没有用 Java 编写的 ADA 解析器?

python - 用 Python 解析 SQL