2016-04-03 22 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")更具可讀性。但是任何一種形式都可以。