2016-09-20 8 views
3

ruamel.yaml.dumpの出力を設定するには?このデータ構造により

d = { 
    (2,3,4): { 
     'a': [1,2], 
     'b': 'Hello World!', 
     'c': 'Voilà!' 
    } 
} 

私はこのYAMLを取得したいと思います:

%YAML 1.2 
--- 
[2,3,4]: 
    a: 
    - 1 
    - 2 
    b: Hello World! 
    c: 'Voilà!' 

は、残念ながら、私はこのフォーマットを取得:

$ print ruamel.yaml.dump(d, default_flow_style=False, line_break=1, explicit_start=True, version=(1,2)) 
%YAML 1.2 
--- 
? !!python/tuple 
- 2 
- 3 
- 4 
: a: 
    - 1 
    - 2 
    b: Hello World! 
    c: !!python/str 'Voilà!' 

私も私が欲しいの出力を設定することはできませんsafe_dumpである。出力で手作業の正規表現を使わずに、どうすればいいですか?あなたが内部の主要な手直しなしruamel.yaml.dump()を使用して、出力として正確に何をしたい得ることができません

def rep(x): 
    return repr([int(y) for y in re.findall('^\??\s*-\s*(\d+)', x.group(0), re.M)]) + ":\n" 
print re.sub('\?(\s*-\s*(\w+))+\s*:', rep, 
    ruamel.yaml.dump(d, default_flow_style=False, line_break=1, explicit_start=True, version=(1,2))) 

答えて

4

:私が見つけ

だけ醜い解決策のようなものです。

  • 好きな出力は、トップレベルのマッピングの値のくぼみ2を有している(キーabなど)とaキーの値である配列の要素のためのインデント4(と-は2つの位置にプッシュされています。マッピングとシーケンスのインデントレベル間の差分を少なくとも必要とします(個別のコレクションでない場合)。 「通常の」フロースタイルは,にのみ出力されます。IIRCこれは現在、どのパラメータでも影響を受けることができません。コレクションを放出する際に、「キーであるシーケンスを放出するときには空間を含まない」ことは困難である。 dump()のオプションを追加するには、いくつかのソースファイルとクラスを変更する必要があります。
ソリューションの表示と

あまり難しい問題:

  • あなたのタプルは魔法のようにタグ!!python/tupleを取り除くための配列に変換する必要があります。すべてのタプルに影響を与えたくないので、これはtupleというサブクラスを作成し、これをシーケンスとして表現することで最もよく行われます(実際にはキーとして使用される場合に限りリストとしてタプルを表現することもできます)。 comments.CommentedKeySeqを使用することができます(ruamel.yaml>=0.12.14とすると、使用時に適切な表現がサポートされています)ruamel.yaml.round_trip_dump()
  • あなたの鍵は、発光する前にテストしたときに単純な鍵ではないので、 '?'(疑問符、スペース)複雑なマッピングキーを示すにはSequenceStartEventが単純なキーを開始するようにエミッタを変更する必要があります(フロースタイルで、ブロックスタイルでない場合)。そのようなSequenceStartEventは、これはemitter.py:Emitter.check_simple_key()emitter.py:Emitter.expect_block_mapping_key()を変更する必要があります。(の明示的な必要性を示している可能性があります「?」キー上)style属性を持っている。
  • cのためのあなたのスカラー文字列値は、あなたのスカラ文字列Vのに対し、引用符を取得します値はbではありません。 ruamel.yamlの出力では、異なる種類のものを作成するだけで、そのような違いを得ることができます。例えば。それはタイプscalarstring.SingleQuotedScalarString()(とround_trip_dump()を使用して)。

そうした場合:

import sys 
import ruamel.yaml 
from ruamel.yaml.comments import CommentedMap, CommentedKeySeq 
assert ruamel.yaml.version_info >= (0, 12, 14) 

data = CommentedMap() 
data[CommentedKeySeq((2, 3, 4))] = cm = CommentedMap() 
cm['a'] = [1, 2] 
cm['b'] = 'Hello World!' 
cm['c'] = ruamel.yaml.scalarstring.SingleQuotedScalarString('Voilà!') 

ruamel.yaml.round_trip_dump(data, sys.stdout, explicit_start=True, version=(1, 2)) 

あなたが得るだろう:離れて2の今一貫したインデントレベルから

%YAML 1.2 
--- 
[2, 3, 4]: 
    a: 
    - 1 
    - 2 
    b: Hello World! 
    c: 'Voilà!' 

は、フロースタイルの順に余分なスペース、およびround_trip_dumpの必要な使用は、あなたが大規模なリワークなしであなたが望むものにあなたを近づけるでしょう。

上記のコードが醜いかどうかはもちろん味わいの問題かどうか。

ruamel.yaml.round_trip_load(preserve_quotes=True)を使用してロードすると、出力は偶然にも往復します。


引用符オーバー制御は必要ありませんし、どちらも重要なマッピング・キーの順序でされていない場合、あなたはまた、通常のダンパーパッチを適用することができます。そして、あなたは、通常のシーケンスを使用することができます

def my_key_repr(self, data): 
    if isinstance(data, tuple): 
     print('data', data) 
     return self.represent_sequence(u'tag:yaml.org,2002:seq', data, 
             flow_style=True) 
    return ruamel.yaml.representer.SafeRepresenter.represent_key(self, data) 

ruamel.yaml.representer.Representer.represent_key = my_key_repr 

を:

data = {} 
data[(2, 3, 4)] = cm = {} 
cm['a'] = [1, 2] 
cm['b'] = 'Hello World!' 
cm['c'] = 'Voilà!' 

ruamel.yaml.dump(data, sys.stdout, allow_unicode=True, explicit_start=True, version=(1, 2)) 

はあなたを与えるだろう。

%YAML 1.2 
--- 
[2, 3, 4]: 
    a: [1, 2] 
    b: Hello World! 
    c: Voilà! 

allow_unicode=Trueを使用して、出力にユニコードを明示的に許可する必要があります(デフォルトはround_trip_dump())。


免責事項を¹:私はruamel.yamlの著者です。

+0

どのような回答です! – nowox

+0

私は 'ruamel.yaml.version_info> =(0,12,14)' - > '(Nowoxのstackoverflowの質問39595807からのメッセージ)' – nowox

+0

あなたの解決策に大きな問題があることは間違いありません。正規のPython辞書をあなたの構造に変換することはできません。私は、データ構造を 'CommentedMap'などで手作業で解析し、期待される結果に到達する必要があります。示されているように、これは実現可能ですが、もし辞書がすでに存在するならば、エレガントではありません。 – nowox

関連する問題