【问题标题】:Can't get pyparsing Dict() to return nested dictionary无法让 pyparsing Dict() 返回嵌套字典
【发布时间】:2012-04-17 05:55:06
【问题描述】:

我正在尝试解析表单的字符串:

'foo(bar:baz;x:y)'

我希望以嵌套字典的形式返回结果,即对于上述字符串,结果应如下所示:

{ 'foo' : { 'bar' : 'baz', 'x' : 'y' } }

尽管有很多 Dict() 和 Group() 的组合,但我无法让它工作。我的(其中一个版本的)语法如下所示:

import pyparsing as pp
field_name = pp.Word( pp.alphanums )
field_value = pp.Word( pp.alphanums )
colon = pp.Suppress( pp.Literal( ':' ) )

expr = pp.Dict( 
    pp.Group( 
        field_name + \
        pp.nestedExpr( 
            content = pp.delimitedList( 
                 pp.Group( field_name + colon + field_value ), 
                 delim = ';' 
            ) 
        ) 
    ) 
)

现在,结果如下:

In [62]: str = 'foo(bar:baz;x:y)'

In [63]: expr.parseString( str ).asList()
Out[63]: [['foo', [['bar', 'baz'], ['x', 'y']]]]

In [64]: expr.parseString( str ).asDict()
Out[64]: {'foo': ([(['bar', 'baz'], {}), (['x', 'y'], {})], {})}

In [65]: print( expr.parseString( str ).dump() )
Out[65]: [['foo', [['bar', 'baz'], ['x', 'y']]]]
         - foo: [['bar', 'baz'], ['x', 'y']]

所以asList() 版本对我来说看起来相当不错,应该会产生一本我想要的字典。当然,鉴于(我理解它的方式,请纠正我)Dict() 将通过使用列表的第一个元素作为键并将所有其余元素作为字典中该键的值来解析标记列表。这在字典没有嵌套的范围内有效。例如在这种情况下:

expr = pp.Dict( 
    pp.delimitedList( 
        pp.Group( field_name + colon + field_value ), 
        delim = ';' 
    ) 
)

In [76]: expr.parseString( 'foo:bar;baz:x' ).asDict()
Out[76]: {'baz': 'x', 'foo': 'bar'}

所以,问题是第一种情况(以及我对问题的理解)有什么问题,或者 Dict() 可能无法应对这种情况?我可以使用 asList() 并将其手动转换为字典,但我宁愿让 pyparsing 这样做:)

任何帮助或指导将不胜感激。

谢谢。

【问题讨论】:

  • OBE - 从 pyparsing 2.1.0(2016 年 2 月)开始,asDict() 也将 dict-ify 嵌套的 ParseResults。

标签: python dictionary nested pyparsing


【解决方案1】:

两个问题:

  • 您在 pp.delimitedList 周围缺少 pp.Dict 以使内部结果上的 asDict 正常工作
  • 您只在最外层的ParsingResult 实例上调用asDict,而将内部的ParsingResult 留下“未解释”

我尝试了以下方法:

from pyparsing import *
field_name = field_val = Word(alphanums)
colon = Suppress(Literal(':'))

expr = Dict(Group(
    field_name +
    nestedExpr(content =
        Dict(delimitedList( 
            Group(field_name + colon + field_value), 
            delim = ';' 
        ))
    )
))

然后这样使用:

>>> res = expr.parseString('foo(bar:baz;x:y)')
>>> type(res['foo'])
<class 'pyparsing.ParseResults'>
>>> { k:v.asDict() for k,v in res.asDict().items() }
{'foo': {'x': 'y', 'bar': 'baz'}}

【讨论】:

  • 很好地抓住了失踪的pp.Dict。此外,尝试打印res.dump() 以查看嵌套的键和值。 (由于res 是一个 ParseResults 对象,它将支持嵌套的 dict 样式访问,而无需使用 asDict 进行转换:res['foo']['x'] 给出 'y';或者只要键是不错的 Python 标识符,您就可以使用点属性表示法:@ 987654333@ 给出'baz'。)
  • 嗨@Paul,很高兴收到作者本人的赞美:) 我发现res.dump() 并没有比str(res) 提供更多信息,但也许我只是不知道如何解释它?我应该说,以前从未使用过 pyparsing。
  • 非常感谢尼克拉斯!我不知道结果中还有 ParseResults 实例,我认为它们已经是列表或字典。保罗 - 感谢关于使用 as dict 而不进行转换的提示,这实际上可能在我正在处理的工作中派上用场! :)
  • 我也花了一点时间弄清楚,因为字符串表示与 Python 数据结构的表示相同。 @Paul:表示不包含有关类型的提示是否有原因?我想这将是一个有用的功能:)
  • res.dump() 应该显示嵌套的标记列表,然后是任何命名结果的缩进树结构 - 对于这个简单的示例应该相当简单。 ParseResults 的 str() 表示显示标记列表,然后是命名结果的 dict 样式 repr,完全作为一个元组。我发现 str() 的输出实际上有点难看,而且更喜欢 dump()。至于实际显示一些类型的指示,嵌套结果会变得更加丑陋,因为正如您所发现的,不仅外部对象是 ParseResults,而且所有内部嵌套对象也是如此。
猜你喜欢
  • 1970-01-01
  • 2017-12-27
  • 2013-11-30
  • 2016-10-06
  • 2014-06-02
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多