2013-06-26 49 views
2

我試圖用驚人的Python庫pyparsing解析文件,但我有很多的問題,正確地分析這個文件......不能與pyparsing

我試圖解析該文件是這樣的:

sectionOne: 
    list: 
    - XXitem 
    - XXanotherItem 
    key1: value1 
    product: milk 
    release: now 
    subSection: 
    skey : sval 
    slist: 
    - XXitem 
    mods: 
    - XXone 
    - XXtwo 
    version: last 
sectionTwo: 
    base: base-0.1 
    config: config-7.0-7 

正如你看到的是一個鋸齒狀的配置文件,而這或多或少是我如何試圖定義語法

  • 的文件可以有一個或多個部分
  • 每個部分由部分名稱和部分內容組成。
  • 每個部分都有一個縮進內容
  • 每個部分的內容可以有一對或多對鍵/值或子部分。
  • 每個值可以只是一個單詞或一個項目列表。
  • 項目列表是一組一個或多個項目。
  • 的每個項目都是一個連字符+一個名稱以「XX」

我試圖創建一個使用pyparsing但沒有成功這個語法。

import pprint 
import pyparsing 
NEWLINE = pyparsing.LineEnd().suppress() 
VALID_CHARACTERS = pyparsing.srange("[a-zA-Z0-9_\-\.]") 
COLON = pyparsing.Suppress(pyparsing.Literal(":")) 
HYPHEN = pyparsing.Suppress(pyparsing.Literal("-")) 
XX = pyparsing.Literal("XX") 

list_item = HYPHEN + pyparsing.Combine(XX + pyparsing.Word(VALID_CHARACTERS)) 
list_of_items = pyparsing.Group(pyparsing.OneOrMore(list_item)) 

key = pyparsing.Word(VALID_CHARACTERS) + COLON 
pair_value = pyparsing.Word(VALID_CHARACTERS) + NEWLINE 
value = (pair_value | list_of_items) 

pair = pyparsing.Group(key + value) 

indentStack = [1] 

section = pyparsing.Forward() 
section_name = pyparsing.Word(VALID_CHARACTERS) + COLON 
section_value = pyparsing.OneOrMore(pair | section) 
section_content = pyparsing.indentedBlock(section_value, indentStack, True) 

section << pyparsing.Group(section_name + section_content) 

parser = pyparsing.OneOrMore(section) 

def main(): 
    try: 
     with open('simple.info', 'r') as content_file: 
      content = content_file.read() 

      print "content:\n", content 
      print "\n" 
      result = parser.parseString(content) 
      print "result1:\n", result 
      print "len", len(result) 

      pprint.pprint(result.asList()) 
    except pyparsing.ParseException, err: 
     print err.line 
     print " " * (err.column - 1) + "^" 
     print err 
    except pyparsing.ParseFatalException, err: 
     print err.line 
     print " " * (err.column - 1) + "^" 
     print err 


if __name__ == '__main__': 
    main() 

這是結果:

result1: 
    [['sectionOne', [[['list', ['XXitem', 'XXanotherItem']], ['key1', 'value1'], ['product', 'milk'], ['release', 'now'], ['subSection', [[['skey', 'sval'], ['slist', ['XXitem']], ['mods', ['XXone', 'XXtwo']], ['version', 'last']]]]]]], ['sectionTwo', [[['base', 'base-0.1'], ['config', 'config-7.0-7']]]]] 
    len 2 
    [ 
    ['sectionOne', 
    [[ 
     ['list', ['XXitem', 'XXanotherItem']], 
     ['key1', 'value1'], 
     ['product', 'milk'], 
     ['release', 'now'], 
     ['subSection', 
      [[ 
       ['skey', 'sval'], 
       ['slist', ['XXitem']], 
       ['mods', ['XXone', 'XXtwo']], 
       ['version', 'last'] 
      ]] 
     ] 
    ]] 
    ], 
    ['sectionTwo', 
    [[ 
     ['base', 'base-0.1'], 
     ['config', 'config-7.0-7'] 
    ]] 
    ] 
    ] 

正如你可以看到我有兩個主要問題:

1.-每一部分內容嵌套兩次進入名單

2 。 - 當「subSection」屬於「sectionOne」時,關鍵「版本」被解析。

我的真實目標是爲了能夠獲得python嵌套字典結構的鍵和值,以便輕鬆提取每個字段的信息,但pyparsing.Dict對我來說是晦澀難懂的。

任何人都可以幫我嗎?

在此先感謝

(抱歉長後)

+2

你的配置格式看起來像YAML。難道你不能只用[PyYAML](http://pyyaml.org/)而不是「手動」解析? –

+0

感謝您的評論@NikitaNemkin。是的,我可以使用PyYAM,事實上,這正是我們現在正在使用的,但是我必須解析的文件來自利益相關者,往往會引入較小的修改,所以我們想要開發一些內部的解析器以便能夠更改它相應地 – thamurath

回答

1

你真的是相當接近 - 恭喜,縮進解析器是不是最容易與pyparsing寫。

看看註釋的更改。那些標有'A'的是修改你的兩個陳述問題的改變。那些用'B'標記的添加Dict構造,以便您可以使用config中的名稱作爲嵌套結構訪問解析的數據。

最大的罪魁禍首是indentedBlock爲你做了一些額外的分組,這妨礙了Dict的名稱 - 值關聯。使用ungroup剝離那讓字典查看底層對。

與pyparsing祝你好運!

import pprint 
import pyparsing 
NEWLINE = pyparsing.LineEnd().suppress() 
VALID_CHARACTERS = pyparsing.srange("[a-zA-Z0-9_\-\.]") 
COLON = pyparsing.Suppress(pyparsing.Literal(":")) 
HYPHEN = pyparsing.Suppress(pyparsing.Literal("-")) 
XX = pyparsing.Literal("XX") 

list_item = HYPHEN + pyparsing.Combine(XX + pyparsing.Word(VALID_CHARACTERS)) 
list_of_items = pyparsing.Group(pyparsing.OneOrMore(list_item)) 

key = pyparsing.Word(VALID_CHARACTERS) + COLON 
pair_value = pyparsing.Word(VALID_CHARACTERS) + NEWLINE 
value = (pair_value | list_of_items) 

#~ A: pair = pyparsing.Group(key + value) 
pair = (key + value) 

indentStack = [1] 

section = pyparsing.Forward() 
section_name = pyparsing.Word(VALID_CHARACTERS) + COLON 
#~ A: section_value = pyparsing.OneOrMore(pair | section) 
section_value = (pair | section) 

#~ B: section_content = pyparsing.indentedBlock(section_value, indentStack, True) 
section_content = pyparsing.Dict(pyparsing.ungroup(pyparsing.indentedBlock(section_value, indentStack, True))) 

#~ A: section << Group(section_name + section_content) 
section << (section_name + section_content) 

#~ B: parser = pyparsing.OneOrMore(section) 
parser = pyparsing.Dict(pyparsing.OneOrMore(pyparsing.Group(section))) 

現在不是pprint(result.asList())你可以寫:

print (result.dump()) 

展現快譯通層次:

[['sectionOne', ['list', ['XXitem', 'XXanotherItem']], ... etc. ... 
- sectionOne: [['list', ['XXitem', 'XXanotherItem']], ... etc. ... 
    - key1: value1 
    - list: ['XXitem', 'XXanotherItem'] 
    - mods: ['XXone', 'XXtwo'] 
    - product: milk 
    - release: now 
    - subSection: [['skey', 'sval'], ['slist', ['XXitem']]] 
    - skey: sval 
    - slist: ['XXitem'] 
    - version: last 
- sectionTwo: [['base', 'base-0.1'], ['config', 'config-7.0-7']] 
    - base: base-0.1 
    - config: config-7.0-7 

讓你寫這樣的語句:

print (result.sectionTwo.base) 
+1

感謝您的快速響應。它現在完美的工作。你的圖書館很有趣,只是有點缺乏文檔。再次感謝和一個非常好的工作! – thamurath