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

时间:2014-07-27 15:29:48

标签: python parsing 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

这是我要解析的表达式:

  

&#34;(2 * 3)+ 20/5 - 1&#34;

这是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中,它显示其中的所有术语(即&#39; +&#39;,&#39; 20.0 / 5.0&#39;,&#39; - &#39;,&#39; 1.0&#39;),它应该是运算符和术语列表。使用dump()函数时,它只显示最后一个运算符和术语(即&#39; - &#39;,&#39; 1.0&#39;)。 任何人都可以帮我理解这个吗?有什么东西我错过了吗?对于我错过的任何事情都很抱歉。

1 个答案:

答案 0 :(得分:2)

如果dump()asXML()之间存在差异,我更有可能将其视为asXML()中的错误。这种方法被迫做了一些&#34;猜测&#34;关于什么是想要的,我可以很容易地看到它在某些情况下猜错了。

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']]

如果您将结果名称添加到原始未分组解析器中,我们会看到这一点(我使用&#34;新&#34;可调用语法而不是罗嗦&分散注意力&#34; setResultsName&#34;调用格式):

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

了解我们现在所知道的关于未分组结果的内容,如果我们要求result.name,我们应该得到哪个名字?

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

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

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

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

    parser = OneOrMore(name.setResultsName(&#34; name&#34;,listAllItems = True)+ integer.setResultsName(&#34; age&#34;,listAllItems = True))

    或者如果使用缩写的可调用格式,请添加&#39; *&#39;到结果名称的末尾:

    parser = OneOrMore(名称(&#34;名称*&#34;)+整数(&#34;年龄*&#34;))

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

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

如果您希望asXML()使用标记#34; person&#34;标记每个群组,请将该名称添加到群组中,并附上&#39; *&#39;抓住他们。

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

(这已经是一个冗长的答案,所以我遗漏了这些测试中的dump()和asXML()输出 - 留给OP和未来读者的练习。)