2016-04-10 7 views
2

IBM Rhapsody sbsファイル形式のパーサをビルドします。しかし残念ながら、再帰部分は期待どおりに機能しません。ルールpp.Word(pp.printables + " ")はおそらく;{}にも一致するため問題になります。しかし、少なくとも;も値の一部とすることができます。値の再帰をリストするリスト(ibm rhapsody)

import pyparsing as pp 
import pprint 


TEST = r"""{ foo 
    - key = bla; 
    - value = 1243; 1233; 1235; 
    - _hans = "hammer 
    time"; 
    - HaMer = 765; 786; 890; 
    - value = " 
    #pragma LINK_INFO DERIVATIVE \"mc9s12xs256\" 
     "; 
    - _mText = 12.11.2015::13:20:0; 
    - value = "war"; "fist"; 
    - _obacht = "fish,car,button"; 
    - _id = gibml c0d8-4535-898f-968362779e07; 
    - bam = { boing 
     - key = bla; 
    } 
    { boing 
     - key = bla; 
    } 
} 
""" 


def flat(loc, toks): 
    if len(toks[0]) == 1: 
     return toks[0][0] 

assignment = pp.Suppress("-") + pp.Word(pp.alphanums + "_") + pp.Suppress("=") 

value = pp.OneOrMore(
    pp.Group(assignment + (
     pp.Group(pp.OneOrMore(
      pp.QuotedString('"', escChar="\\", multiline=True) + 
      pp.Suppress(";"))).setParseAction(flat) | 
     pp.Word(pp.alphas) + pp.Suppress(";") | 
     pp.Word(pp.printables + " ") 
    )) 
) 

expr = pp.Forward() 

expr = pp.Suppress("{") + pp.Word(pp.alphas) + (
    value | (assignment + expr) | expr 
) + pp.Suppress("}") 
expr = expr.ignore(pp.pythonStyleComment) 


print TEST 
pprint.pprint(expr.parseString(TEST).asList()) 

出力:

% python prase.py              
{ foo 
    - key = bla; 
    - value = 1243; 1233; 1235; 
    - _hans = "hammer 
    time"; 
    - HaMer = 765; 786; 890; 
    - value = " 
    #pragma LINK_INFO DERIVATIVE \"mc9s12xs256\" 
     "; 
    - _mText = 12.11.2015::13:20:0; 
    - value = "war"; "fist"; 
    - _obacht = "fish,car,button"; 
    - _id = gibml c0d8-4535-898f-968362779e07; 
    - bam = { boing 
     - key = bla; 
    } 
    { boing 
     - key = bla; 
    } 
} 

['foo', 
['key', 'bla'], 
['value', '1243; 1233; 1235;'], 
['_hans', 'hammer\n time'], 
['HaMer', '765; 786; 890;'], 
['value', '\n #pragma LINK_INFO DERIVATIVE "mc9s12xs256"\n  '], 
['_mText', '12.11.2015::13:20:0;'], 
['value', ['war', 'fist']], 
['_obacht', 'fish,car,button'], 
['_id', 'gibml c0d8-4535-898f-968362779e07;'], 
['bam', '{ boing'], 
['key', 'bla']] 
+0

TESTに入力ミスはありますか? ' - bam {boingなど} 'の後の最後のグループは' - something = {boing \ n- key = bla; } '?このフォーマットがどんなものであるかを知ることは難しく、いろいろなOneOrMoreがそこに投げ込まれています。私はあなたが停止し、BNFを最初に書いたとすれば、物事はより明確になると思います。 – PaulMcG

+0

また、 'pp.Word(printables + '')'のように、あまりにも多く一致する式に対しては強くお勧めします。-ypesarsingのWordクラスの最新バージョンを読み込みます。これには 'excludeChars'引数が含まれています。 'Word(printable、excludeChars = ';')'と書いてください。 – PaulMcG

+0

悲しいことに、フォーマットは正しいです。実際の例https://github.com/mansam/exploring-rhapsody/blob/master/LightSwitch/LightSwitch.rpy – delijati

答えて

2

うわー、それは1つの厄介なモデル形式であります!私はこれがあなたを近づけると思います。私は、有効な値式が何であるかを特徴づけることから始めました。各グループには、 ';'で終了する属性定義、または{}}で囲んだネストされたオブジェクトが含まれることがあります。各オブジェクトには、オブジェクトタイプを示す先頭の識別子が含まれていました。

難しい問題は、私が ' - '、 '{'、 '}'でなければ、私は 'value_word'という名前の非常に一般的なトークンでした。 'value_word'の定義における否定的な先読みによってこれが処理されます。ここでの重要な問題は、ではなく、に '' value_word 'の有効な文字として' 'を含めることができましたが、その代わりに、pyparsingにデフォルトの空白をスキップさせて1つ以上の' 「attr_value」です。

最終キッカー(テストケースで見つかったが、一例では、あなたがにリンクされていない)は、属性「割り当て」のため、この行だった:

  - m_pParent = ; 

のでATTR_VALUEは空の文字列を許可しなければなりませんでしたまた、あなたのテスト文字列の場合

from pyparsing import * 

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

ident = Word(alphas + '_', alphanums+'_').setName("ident") 
guid = Group('GUID' + Combine(Word(hexnums)+('-'+Word(hexnums))*4)) 
qs = QuotedString('"', escChar="\\", multiline=True) 
character_literal = Combine("'" + oneOf(list(printables+' ')) + "'") 
value_word = ~DASH + ~LBRACE + ~RBRACE + Word(printables, excludeChars=';').setName("value_word") 

value_atom = guid | qs | character_literal | value_word 

object_ = Forward() 

attr_value = OneOrMore(object_) | Optional(delimitedList(Group(value_atom+OneOrMore(value_atom))|value_atom, ';')) + SEMI 
attr_value.setName("attr_value") 
attr_defn = Group(DASH + ident("name") + EQ + Group(attr_value)("value")) 
attr_defn.setName("attr_defn") 

object_ <<= Group(
    LBRACE + ident("type") + 
    Group(ZeroOrMore(attr_defn | object_))("attributes") + 
    RBRACE 
    ) 

object_.parseString(TEST).pprint() 

それは与える:私はこれらの構造を処理するのに役立つかもしれない結果名を追加

[['foo', 
    [['key', ['bla']], 
    ['value', ['1243', '1233', '1235']], 
    ['_hans', ['hammer\n time']], 
    ['HaMer', ['765', '786', '890']], 
    ['value', ['\n #pragma LINK_INFO DERIVATIVE "mc9s12xs256"\n  ']], 
    ['_mText', ['12.11.2015::13:20:0']], 
    ['value', ['war', 'fist']], 
    ['_obacht', ['fish,car,button']], 
    ['_id', [['gibml', 'c0d8-4535-898f-968362779e07']]], 
    ['bam', [['boing', [['key', ['bla']]]], ['boing', [['key', ['bla']]]]]]]]] 

object_.parseString(TEST).dump()を使用すると、この出力を与える:大手バージョンラインが除去されると

[['foo', [['key', ['bla']], ['value', ['1243', '1233', '1235']], ['_hans', ['hammer\n time']], ... 
[0]: 
    ['foo', [['key', ['bla']], ['value', ['1243', '1233', '1235']], ['_hans', ['hammer\n time']], ... 
    - attributes: [['key', ['bla']], ['value', ['1243', '1233', '1235']], ['_hans', ['hammer... 
    [0]: 
     ['key', ['bla']] 
     - name: key 
     - value: ['bla'] 
    [1]: 
     ['value', ['1243', '1233', '1235']] 
     - name: value 
     - value: ['1243', '1233', '1235'] 
    [2]: 
     ['_hans', ['hammer\n time']] 
     - name: _hans 
     - value: ['hammer\n time'] 
    [3]: 
     ['HaMer', ['765', '786', '890']] 
     - name: HaMer 
     - value: ['765', '786', '890'] 
    [4]: 
     ['value', ['\n #pragma LINK_INFO DERIVATIVE "mc9s12xs256"\n  ']] 
     - name: value 
     - value: ['\n #pragma LINK_INFO DERIVATIVE "mc9s12xs256"\n  '] 
    [5]: 
     ['_mText', ['12.11.2015::13:20:0']] 
     - name: _mText 
     - value: ['12.11.2015::13:20:0'] 
    [6]: 
     ['value', ['war', 'fist']] 
     - name: value 
     - value: ['war', 'fist'] 
    [7]: 
     ['_obacht', ['fish,car,button']] 
     - name: _obacht 
     - value: ['fish,car,button'] 
    [8]: 
     ['_id', [['gibml', 'c0d8-4535-898f-968362779e07']]] 
     - name: _id 
     - value: [['gibml', 'c0d8-4535-898f-968362779e07']] 
     [0]: 
      ['gibml', 'c0d8-4535-898f-968362779e07'] 
    [9]: 
     ['bam', [['boing', [['key', ['bla']]]], ['boing', [['key', ['bla']]]]]] 
     - name: bam 
     - value: [['boing', [['key', ['bla']]]], ['boing', [['key', ['bla']]]]] 
     [0]: 
      ['boing', [['key', ['bla']]]] 
      - attributes: [['key', ['bla']]] 
      [0]: 
       ['key', ['bla']] 
       - name: key 
       - value: ['bla'] 
      - type: boing 
     [1]: 
      ['boing', [['key', ['bla']]]] 
      - attributes: [['key', ['bla']]] 
      [0]: 
       ['key', ['bla']] 
       - name: key 
       - value: ['bla'] 
      - type: boing 
    - type: foo 

また成功し、リンクされている例を解析します。

+0

ニース。私は '負の数'、 '日付'と先頭の 'ヘッダ'の扱いを追加しましたが、うまくいったのです。私は 'NotAny(〜)'演算子を認識していませんでしたが、すべての '区切りリスト'または 'オブジェクト'を集計しました。私は大きなモデル(700kB)で試してみました。それを解析するには25秒かかりました。私はあなたのレポをフォークし、私はcythonで遊んでいます。今のところ私は18歳になった。私は結果をこのレポに投​​稿します。https://github.com/delijati/pyparsing – delijati

+0

フォークまたはサイホンの道を遠くに進める前に、packrat解析を有効にしてみてください。常に役立つとは限りませんが、再帰的な文法の場合、結果は10〜100倍になります。 – PaulMcG

+0

Tried 'pp。enablePackrat() 'を使用していましたが、メモリ消費量は屋根から最大で4倍になりました。\t 私は 'resetCache'を呼び出すことが役に立ちます。 http://stackoverflow.com/questions/26591485/incremental-but-complete-parsing-with-pyparsing。キャッシュを 'ls_cache'で置き換えることもできます。これには' maxsize'があります。 – delijati

関連する問題