在pyparsing中嵌套结构的技巧

我正在努力用PyParsing解析嵌套结构。 我搜索了很多PyParsing的'嵌套'示例用法,但我没有看到如何解决我的问题。

以下是我的内部结构:

texture_unit optionalName
{
    texture required_val
    prop_name1 prop_val1
    prop_name2 prop_val1
}

这里是我的外部结构看起来像,但它可以包含零个或更多的内部结构。

pass optionalName
{
    prop_name1 prop_val1
    prop_name2 prop_val1

    texture_unit optionalName
    {
        // edit 2: showing use of '.' character in value
        texture required_val.file.name optional_val // edit 1: forgot this line in initial post.

        // edit 2: showing potentially multiple values
        prop_name3 prop_val1 prop_val2
        prop_name4 prop_val1
    }
}

我正在成功解析内部结构。 这是我的代码。

prop_ = pp.Group(pp.Word(pp.alphanums+'_')+pp.Group(pp.OneOrMore(pp.Word(pp.alphanums+'_'+'.'))))
texture_props_ = pp.Group(pp.Literal('texture') + pp.Word(pp.alphanums+'_'+'.')) + pp.ZeroOrMore(prop_)
texture_ = pp.Forward()
texture_ << pp.Literal('texture_unit').suppress() + pp.Optional(pp.Word(pp.alphanums+'_')).suppress() + pp.Literal('{').suppress() + texture_props_ + pp.Literal('}').suppress()

这是我尝试解析外部结构,

pass_props_ = pp.ZeroOrMore(prop_)
pass_ = pp.Forward()
pass_ << pp.Literal('pass').suppress() + pp.Optional(pp.Word(pp.alphanums+'_'+'.')).suppress() + pp.Literal('{').suppress() + pass_props_ + pp.ZeroOrMore(texture_) + pp.Literal('}').suppress()

当我说:pass_.parseString(testPassStr)

我在控制台中看到“}”预期的错误。

我认为这与C结构示例非常相似,但我不确定什么是缺少的魔法。 我也很好奇如何在使用nestedExpr时控制结果数据结构。


有两个问题:

  • 在你的语法中,你已经按照texture_unit块的要求标记了texture文字,但在第二个例子中没有texture
  • 在第二个示例中, pass_props_texture_unit optionalName一致。 在它之后, pp.Literal('}')期望} ,但给出{ 。 这是错误的原因。
  • 我们可以通过像这样更改pass_规则来检查它:

    pass_ << pp.Literal('pass').suppress() + pp.Optional(pp.Word(pp.alphanums+'_'+'.')).suppress() + 
                 pp.Literal('{').suppress() + pass_props_
    
    print pass_.parseString(s2)
    

    它让我们跟随输出:

    [['prop_name', ['prop_val', 'prop_name', 'prop_val', 'texture_unit', 'optionalName']]]
    

    我们可以看到pass_props_texture_unit optionalName一致。
    所以,我们想要做的是: prop_可以包含alphanums_. ,但不能与texture_unit文字匹配。 我们可以用regex和负面看法来做到这一点:

    prop_ = pp.Group(  pp.Regex(r'(?!texture_unit)[a-z0-9_]+')+ pp.Group(pp.OneOrMore(pp.Regex(r'(?!texture_unit)[a-z0-9_.]+'))) )
    

    最后,工作示例如下所示:

    import pyparsing as pp
    
    s1 = '''texture_unit optionalName
        {
        texture required_val
        prop_name prop_val
        prop_name prop_val
    }'''
    
    prop_ = pp.Group(  pp.Regex(r'(?!texture_unit)[a-z0-9_]+')+ pp.Group(pp.OneOrMore(pp.Regex(r'(?!texture_unit)[a-z0-9_.]+'))) )
    texture_props_ = pp.Group(pp.Literal('texture') + pp.Word(pp.alphanums+'_'+'.')) + pp.ZeroOrMore(prop_)
    texture_ = pp.Forward()
    texture_ = pp.Literal('texture_unit').suppress() + pp.Word(pp.alphanums+'_').suppress() +
               pp.Literal('{').suppress() + pp.Optional(texture_props_) + pp.Literal('}').suppress()
    
    print texture_.parseString(s1)
    
    s2 = '''pass optionalName
    {
        prop_name1 prop_val1.name
        texture_unit optionalName1
        {
            texture required_val1
            prop_name2 prop_val12
            prop_name3 prop_val13
        }
        texture_unit optionalName2
        {
            texture required_va2l
            prop_name2 prop_val22
            prop_name3 prop_val23
        }
    }'''
    
    pass_props_ = pp.ZeroOrMore(prop_  )
    pass_ = pp.Forward()
    
    pass_ = pp.Literal('pass').suppress() + pp.Optional(pp.Word(pp.alphanums+'_'+'.')).suppress() +
            pp.Literal('{').suppress() + pass_props_ + pp.ZeroOrMore(texture_ ) + pp.Literal('}').suppress()
    
    print pass_.parseString(s2)
    

    输出:

    [['texture', 'required_val'], ['prop_name', ['prop_val', 'prop_name', 'prop_val']]]
    [['prop_name1', ['prop_val1.name']], ['texture', 'required_val1'], ['prop_name2', ['prop_val12', 'prop_name3', 'prop_val13']], ['texture', 'required_va2l'], ['prop_name2', ['prop_val22', 'prop_name3', 'prop_val23']]]
    

    我正在寻找的答案与使用“Forward”分析器相关,如Cstruct示例中所示(在OP中链接)。

    为嵌套结构定义语法的难点在于定义结构的所有可能的成员类型,它需要包含结构本身,但仍未定义。

    为嵌套结构定义pyparsing语法的“诀窍”是延迟结构的定义,但在定义结构成员时包含结构的“前向声明”版本,因此成员还可以包含结构。 然后将结构语法作为成员列表来完成。

    struct = Forward()
    member = blah | blah2 | struct
    struct << ZeroOrMore( Group(member) )
    

    这也在这里讨论:Pyparsing:将半JSON嵌套明文数据解析为列表

    OP(我的)描述的测试数据和语法不够具体,并且在应该失败时匹配。 @NorthCat正确地在文法中发现了不需要的匹配。 但是,定义许多“负面预测”的建议似乎难以管理。

    我的解决方案并没有明确列出可能的匹配,而是定义了不匹配的内容。 这些匹配是成员关键字,使用'oneOf('用空格分隔的单词列表')。 一旦我指定了所有可能的匹配,我意识到我的结构不是嵌套结构,但实际上深度有限和不同语法的结构描述了每个深度。 所以,我的成员定义不需要前向声明技巧。

    我的成员定义的终止符与Cstruct示例中的不同。 而不是终止于';' (分号)就像在C ++中一样,我的成员定义需要在行尾结束。 在pyparsing中,可以使用'LineEnd'分析器指定行的末尾。 因此,我将我的成员定义为不包含'LineEnd'的值列表,如下所示,请注意在最后定义中使用“Not”(〜)运算符:

    EOL = LineEnd().suppress()
    ident = Word( alphas+"_", alphanums+"_$@#." )
    integer = Word(nums)
    real = Combine(Optional(oneOf('+ -')) + Word(nums) + '.' + Optional(Word(nums)))
    propVal = real | integer | ident
    propList = Group(OneOrMore(~EOL + propVal))
    
    链接地址: http://www.djcxy.com/p/79281.html

    上一篇: the trick to nested structures in pyparsing

    下一篇: how to search json