2

すばらしい python ライブラリを使用してファイルを解析しようとしています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

ご覧のとおり、インデントされた構成ファイルです。これは多かれ少なかれ、文法を定義しようとした方法です

  • ファイルには 1 つ以上のセクションを含めることができます
  • 各セクションは、セクション名とセクションの内容で構成されます。
  • 各セクションにはインデントされたコンテンツがあります
  • 各セクションのコンテンツには、キーと値のペアまたはサブセクションを 1 つ以上含めることができます。
  • 各値は、単一の単語またはアイテムのリストにすることができます。
  • アイテムのリストは、1 つ以上のアイテムのグループです。
  • 各項目はハイフン + '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']
     ]]
     ]
  ]

ご覧のとおり、主な問題が 2 つあります。

1.- 各セクションのコンテンツはリストに 2 回入れ子になっています

2.- キー「version」は、「sectionOne」に属する場合、「subSection」内で解析されます

の本当の目標は、各フィールドの情報を簡単に抽出するためのキーと値を持つ python のネストされた辞書の構造を取得できるようにすることですが、それpyparsing.Dictは私にはわかりにくいものです。

誰でも私を助けてもらえますか?

前もって感謝します

(長文すみません)

4

1 に答える 1

1

あなたは本当にかなり近づいています - おめでとう、インデントされたパーサーは pyparsing で書くのが最も簡単ではありません。

コメントされた変更を見てください。「A」でマークされたものは、2 つの述べられた問題を修正するための変更です。「B」でマークされたものは Dict コンストラクトを追加して、構成内の名前を使用してネストされた構造として解析されたデータにアクセスできるようにします。

最大の原因はindentedBlock、Dict の名前と値の関連付けの邪魔になる余分なグループ化を行うことです。を使用ungroupしてそれを剥がすと、Dict は下にあるペアを見ることができます。

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

Dict 階層を表示するには:

[['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)
于 2013-06-29T15:51:09.773 に答える