2011-03-07 39 views
5

我需要解析一些特殊的數據結構。他們在某種程度上有些類似-C格式,看起來大致是這樣的:如何解析代碼(使用Python)?

Group("GroupName") { 
    /* C-Style comment */ 
    Group("AnotherGroupName") { 
     Entry("some","variables",0,3.141); 
     Entry("other","variables",1,2.718); 
    } 
    Entry("linebreaks", 
      "allowed", 
      3, 
      1.414 
     ); 
} 

我能想到的幾種方法去這個問題。我可以使用正則表達式來「代碼化」代碼。我可以一次讀取一個字符的代碼,並使用狀態機構造我的數據結構。我可以擺脫逗號分隔線並逐行閱讀。我可以編寫一些轉換腳本,將此代碼轉換爲可執行的Python代碼。

是否有一個很好的pythonic方式來解析這樣的文件?
你會如何解析它?

這更多的是關於如何解析字符串的一般問題,而不是那麼多關於這個特定的文件格式。

+3

[本文](http://nedbatchelder.com/text/python-parsers.html)可能會引起您的興趣。 –

回答

6

使用pyparsing(馬克Tolonen,我正要點擊「提交郵報」當你此帖一通),這是非常簡單的 - 見嵌入代碼如下意見:

data = """Group("GroupName") { 
    /* C-Style comment */ 
    Group("AnotherGroupName") { 
     Entry("some","variables",0,3.141); 
     Entry("other","variables",1,2.718); 
    } 
    Entry("linebreaks", 
      "allowed", 
      3, 
      1.414 
     ); 
} """ 

from pyparsing import * 

# define basic punctuation and data types 
LBRACE,RBRACE,LPAREN,RPAREN,SEMI = map(Suppress,"{}();") 
GROUP = Keyword("Group") 
ENTRY = Keyword("Entry") 

# use parse actions to do parse-time conversion of values 
real = Regex(r"[+-]?\d+\.\d*").setParseAction(lambda t:float(t[0])) 
integer = Regex(r"[+-]?\d+").setParseAction(lambda t:int(t[0])) 

# parses a string enclosed in quotes, but strips off the quotes at parse time 
string = QuotedString('"') 

# define structure expressions 
value = string | real | integer 
entry = Group(ENTRY + LPAREN + Group(Optional(delimitedList(value)))) + RPAREN + SEMI 

# since Groups can contain Groups, need to use a Forward to define recursive expression 
group = Forward() 
group << Group(GROUP + LPAREN + string("name") + RPAREN + 
      LBRACE + Group(ZeroOrMore(group | entry))("body") + RBRACE) 

# ignore C style comments wherever they occur 
group.ignore(cStyleComment) 

# parse the sample text 
result = group.parseString(data) 

# print out the tokens as a nice indented list using pprint 
from pprint import pprint 
pprint(result.asList()) 

打印

[['Group', 
    'GroupName', 
    [['Group', 
    'AnotherGroupName', 
    [['Entry', ['some', 'variables', 0, 3.141]], 
    ['Entry', ['other', 'variables', 1, 2.718]]]], 
    ['Entry', ['linebreaks', 'allowed', 3, 1.4139999999999999]]]]] 

(不幸的是,可能會有一些混亂,因爲pyparsing定義了一個「組」類,賦予結構的解析令牌 - 注意條目中的值列表怎麼弄分組,因爲列表表達式是pyparsing集團內部封閉)

+3

你剛剛在O'Reilly書店賺了10美元! – bastibe

1

取決於您需要多久以及語法是否保持不變。如果答案是「經常」和「或多或少」,那麼我會考慮一種方式來表達語法,並用PyPEGLEPL這樣的工具編寫特定的語言解析器。定義解析器規則是一項重要的工作,所以除非你經常需要解析相同類型的文件,否則它可能不一定有效。

但是,如果您查看PyPEG頁面,它會告訴您如何將解析的數據輸出到XML,因此如果該工具沒有給您提供足夠的電源,您可以使用它來生成XML,然後使用例如。 lxml來解析xml。