Python pyparsing中嵌套结构的技巧

Python pyparsing中嵌套结构的技巧,python,nested,pyparsing,Python,Nested,Pyparsing,我正在努力用PyParsing解析嵌套结构。我已经搜索了很多,但我不知道如何解决我的问题 以下是我的内部结构: texture_unit optionalName { texture required_val prop_name1 prop_val1 prop_name2 prop_val1 } 这是我的外部结构,但它可以包含零个或更多的内部结构 pass optionalName { prop_name1 prop_val1 prop_name2 pr

我正在努力用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()
prop_uz=pp.Group(pp.Word(pp.alphanums+''''''')+pp.Group(pp.OneOrMore(pp.Word(pp.alphanums+''+')))
纹理属性=pp.Group(pp.Literal('texture')+pp.Word(pp.alphanums++''+'))+pp.ZeroOrMore(属性属性属性)
纹理=pp.Forward()

有两个问题:

  • 在语法中,您在
    纹理单元
    块中按要求标记了
    纹理
    文字,但在第二个示例中没有
    纹理
  • 在第二个示例中,
    pass\u props\u
    texture\u unit optionalName
    一致。在它之后,
    pp.Literal('}')
    期望
    }
    ,但给出
    {
    。这就是错误的原因
  • 我们可以通过如下更改
    通过
    规则进行检查:

    pass_ << pp.Literal('pass').suppress() + pp.Optional(pp.Word(pp.alphanums+'_'+'.')).suppress() + \
                 pp.Literal('{').suppress() + pass_props_
    
    print pass_.parseString(s2)
    
    我们可以看到
    pass\u props\u
    texture\u unit optionalName

    相一致,因此,我们要做的是:
    prop\u
    可以包含
    字母数
    \ucode>和
    但不能与
    texture\u unit
    文字匹配。我们可以使用
    regex
    和:

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

    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) )
    

    1.你是对的,我的嵌套示例缺少必需的“texture”属性。这是发布时的一个输入错误。我将在帖子中更正它。@cyrf第二项和他的解决方案如何?关于#2,谢谢你的建议。我仍在测试它。我正在试图理解为什么C结构中不需要“负面展望”t解析器示例,支持嵌套的C结构(在我的原始文章中链接)。新定义的“prop_”打破了对内部结构的解析。我应该让测试更明确,我试图让它更具一般性和可读性。我现在将编辑我的帖子,以更好地说明我需要什么。你能评论一下为什么C struct示例不需要“负面前瞻”?如果内部结构在pr中没有使用“.”op_val,然后解析内部结构。但是,使用您的更改解析外部结构仍然会产生错误。下面是另一个支持嵌套结构的示例。它似乎使用了“pyparsing.Dict”。所有这些示例都显示了实现嵌套解析的不同方法,其共性是什么?
    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']]]
    
    struct = Forward()
    member = blah | blah2 | struct
    struct << ZeroOrMore( Group(member) )
    
    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))