2016-09-05 6 views
2

私たちは次の文字列pyparsingから結果を得るにはオブジェクトを転送しますか?

string = """ 
object obj1{ 
    attr1 value1; 


    object obj2 { 
     attr2 value2; 
    } 
} 

object obj3{ 
    attr3 value3; 
    attr4 value4; 
} 

""" 

ネストされたオブジェクトがありますがあり、我々はこれを解析するためにフォワードを使用すると仮定しましょう。

from pyparsing import * 
word = Word(alphanums) 

attribute = word.setResultsName("name") 
value = word.setResultsName("value") 

object_grammar = Forward() 

attributes = attribute + value + Suppress(";") + LineEnd().suppress() 
object_type = Suppress("object ") + word.setResultsName("object_type") + Suppress('{') + LineEnd().suppress() 

object_grammar <<= object_type+\ 
    OneOrMore(attributes|object_grammar) + Suppress("}") | Suppress("};") 

for i, (obj, _, _) in enumerate(object_grammar.scanString(string)): 
    print('\n') 
    print('Enumerating over object {}'.format(i)) 
    print('\n') 
    print('This is the object type {}'.format(obj.object_type)) 
    print(obj.asXML()) 
    print(obj.asDict()) 
    print(obj.asList()) 
    print(obj) 
    print(obj.dump()) 

これらは結果です。 obj.asXML()関数にはすべての情報が含まれていますが、フラット化されているため、結果の解析には情報の順序が不可欠です。これはこれを行う最善の方法ですか?私は何かを欠いているに違いない。私はネストされたオブジェクトとネストされていないオブジェクトの両方で、つまりobj1、obj2、obj3の両方で動作するソリューションを希望します。

また、setResultsName('object_type')は、親オブジェクトに対してobject_typeを返しません。上記のプログラムの出力を以下に示します。助言がありますか?

Enumerating over object 0 

This is the object type obj2 

<ITEM> 
    <object_type>obj1</object_type> 
    <name>attr1</name> 
    <value>value1</value> 
    <object_type>obj2</object_type> 
    <name>attr2</name> 
    <value>value2</value> 
</ITEM> 
{'object_type': 'obj2', 'name': 'attr2', 'value': 'value2'} 
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2'] 
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2'] 
['obj1', 'attr1', 'value1', 'obj2', 'attr2', 'value2'] 
- name: attr2 
- object_type: obj2 
- value: value2 


Enumerating over object 1 


This is the object type obj3 

<ITEM> 
    <object_type>obj3</object_type> 
    <name>attr3</name> 
    <value>value3</value> 
    <name>attr4</name> 
    <value>value4</value> 
</ITEM> 
{'object_type': 'obj3', 'name': 'attr4', 'value': 'value4'} 
['obj3', 'attr3', 'value3', 'attr4', 'value4'] 
['obj3', 'attr3', 'value3', 'attr4', 'value4'] 
['obj3', 'attr3', 'value3', 'attr4', 'value4'] 
- name: attr4 
- object_type: obj3 
- value: value4 

答えて

2

入力文字列を正常に処理している間に、文法にいくつか改良を加えることをお勧めします。

再帰的文法を定義するとき、通常、出力結果に構造をいくつか維持したいと考えています。あなたの場合、構造化する論理的な要素は、各オブジェクトの内容で、中かっこで囲まれています。概念的:

object_content = '{' + ZeroOrMore(attribute_defn | object_defn) + '}' 

はその後、支援の表現は、単に(まだ概念的には)次のとおりです。

attribute_defn = identifier + attribute_value + ';' 
object_defn = 'object' + identifier + object_content 

このため、実際のP​​ython/pyparsingは、次のようになります。

LBRACE,RBRACE,SEMI = map(Suppress, "{};") 

word = Word(alphas, alphanums) 
attribute = word 

# expand to include other values if desired, such as ints, reals, strings, etc. 
attribute_value = word 
attributeDefn = Group(word("name") + value("value") + SEMI) 

OBJECT = Keyword("object") 
object_header = OBJECT + word("object_name") 
object_grammar = Forward() 
object_body = Group(LBRACE 
        + ZeroOrMore(object_grammar | attributeDefn) 
        + RBRACE) 
object_grammar <<= Group(object_header + object_body("object_content")) 

Groupが私たちのために2つのことを行いますそれは結果をサブオブジェクトに構造化する。結果レベルを1つのレベルに保ち、別のレベルの結果を保持します(したがって、listAllMatchesの必要はありません)。

今の代わりにscanStringの、あなただけのOneOrMoreを使用して、あなたの入力を処理することができます:私はちょうどあなたのコードに簡単な変更を作り始め

[['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]], ['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]]] 
[0]: 
    ['object', 'obj1', [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]]] 
    - object_content: [['attr1', 'value1'], ['object', 'obj2', [['attr2', 'value2']]]] 
    [0]: 
     ['attr1', 'value1'] 
     - name: attr1 
     - value: value1 
    [1]: 
     ['object', 'obj2', [['attr2', 'value2']]] 
     - object_content: [['attr2', 'value2']] 
     [0]: 
      ['attr2', 'value2'] 
      - name: attr2 
      - value: value2 
     - object_name: obj2 
    - object_name: obj1 
[1]: 
    ['object', 'obj3', [['attr3', 'value3'], ['attr4', 'value4']]] 
    - object_content: [['attr3', 'value3'], ['attr4', 'value4']] 
    [0]: 
     ['attr3', 'value3'] 
     - name: attr3 
     - value: value3 
    [1]: 
     ['attr4', 'value4'] 
     - name: attr4 
     - value: value4 
    - object_name: obj3 

が、致命的ではありました:

print(OneOrMore(object_grammar).parseString(string).dump()) 

を与えますあなたのオリジナルの欠陥。パーサーは、左右の中括弧を2つの別々の式に分けています。これが「機能する」とは、結果のグループ構造を定義する能力を無効にします。

+0

ありがとうPaul!これは素晴らしい作品です!あなたがそれを書いたので今や意味があります。上記の例は、完全なファイルのスニペットです。ファイルの先頭に 'defintion here'のような行が追加されていますが、理解すると' parseString'を使うことはできません。 's.asDict()'を使うことができないことを除いて、うまく動作する '[s、i、j for s object_grammar.scanString(string)]'を使っています。なぜasDictがうまくいかないのか? – kdheepak

2

私はsetResultsNames機能でlistAllMatches=Trueを使用することによってこの問題を回避することができました。これは、情報を取得できる構造を持つasXML()の結果として私に与えられました。それでもXMLの順序に依存しており、namevalueを合わせてattributeにするにはzipを使用する必要があります。私はこの質問を開いたままにして、これを行うより良い方法があるかどうかを確認します。

関連する問題