2016-04-03 70 views
1

我有一个关于嵌套语法的问题。你如何使pyparsing寻找嵌套的语法结构。PyParsing不像预期的那样嵌套语法

from pyparsing import Word, alphas, alphanums, Suppress, LineEnd, LineStart, nums, Or, Group, OneOrMore, Literal, CaselessLiteral, Combine, Optional 

word = Word(alphanums+'_') 

object_type = Suppress("object ")+word.setResultsName("object_type")+Suppress('{')+LineEnd() 

point = Literal('.') 
e = CaselessLiteral('E') 
plusorminus = Literal('+') | Literal('-') 
number = Word(nums) 
integer = Combine(Optional(plusorminus) + number) 
floatnumber = Combine(integer + 
         Optional(point + Optional(number)) + 
         Optional(e + integer) 
        ) 

attribute = word.setResultsName("attribute") 
value = Or([floatnumber, word]).setResultsName("value") 

attributes = Group(attribute+value+Suppress(";")+LineEnd()) 
namespace = Group(object_type+\ OneOrMore(attributes).setResultsName("attributes") + Suppress("}")) 
all = OneOrMore(namespace).setResultsName("namespaces") 

result = all.parseString(glm) 

for n in result.namespaces: 
    print(n) 

以下是我想要解析的例子。第一个命名空间按预期工作。然而第二个不能解析。任何人都可以解释我错过了什么?

"""object object_type1{ 
attr1 0.0111; 
name name_of_object_1; 
} 
object object_type1{ 
attr1 0.02; 
name name_of_object_2; 
    object object_type2{ 
    name name_of_object_3; 
    } 
} 
""" 

回答

1

要定义一个递归语法,即一个具有术语,本身是它自己定义的一部分,你需要使用pyparsing的Forward类。在你的情况下,namespace可以包含属性或嵌套的命名空间。要做到这一点,你首先要确定一种占位符为namespace

namespace = Forward() 

然后当它是时间来定义的内容(包括namespace作为定义的一部分),使用<<=运营商,而不是=

namespace <<= Group(object_type + OneOrMore(attributes|namespace).setResultsName("attributes") + Suppress("}")) 
all = OneOrMore(namespace).setResultsName("namespaces") 

除此之外,你的解析器应该工作得很好。

只是一对夫妇的其他提示:

  • 我最近添加的pprint()方法来简化上市了ParseResults对象的内容。尝试使用result.pprint()而不是您现在使用的for循环。

  • 您并不需要在输出中使用换行符,因此请将所有LineEnd()条款替换为LineEnd().suppress()--这样可以稍微提高结果。

  • 我不确定在这种情况下结果名称是否真的为你做了很多事情。但我发现使用expr("name")expr.setResultsName("name")更具可读性。但是任何一种形式都可以。