44

短い文字列属性と長い複数行の文字列属性を持つオブジェクトがあります。短い文字列を YAML 引用スカラーとして書き、複数行の文字列をリテラル スカラーとして書きたいと思います。

my_obj.short = "Hello"
my_obj.long = "Line1\nLine2\nLine3"

YAML を次のようにしたいと思います。

short: "Hello"
long: |
  Line1
  Line2
  Line3

これを行うように PyYAML に指示するにはどうすればよいですか? を呼び出すとyaml.dump(my_obj)、dict のような出力が生成されます。

{long: 'line1

    line2

    line3

    ', short: Hello}

(なぜ long がそのようにダブルスペースになっているのかわかりません...)

属性の処理方法を PyYAML に指示できますか? 順序とスタイルの両方に影響を与えたいです。

4

4 に答える 4

45

@lbt のアプローチに恋をして、次のコードを取得しました。

import yaml

def str_presenter(dumper, data):
  if len(data.splitlines()) > 1:  # check for multiline string
    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
  return dumper.represent_scalar('tag:yaml.org,2002:str', data)

yaml.add_representer(str, str_presenter)

# to use with safe_dump:
yaml.representer.SafeRepresenter.add_representer(str, str_presenter)

すべての複数行の文字列をブロック リテラルにします。

サルのパッチ部分を避けようとしていました。@lbt と @JFSebastian の功績。

于 2015-10-23T10:17:50.883 に答える
31

ブロックリテラルまたは折り畳まれたブロックとして長い文字列のダンプをサポートする Python の yaml ライブラリに基づいていますか?

import yaml
from collections import OrderedDict

class quoted(str):
    pass

def quoted_presenter(dumper, data):
    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
yaml.add_representer(quoted, quoted_presenter)

class literal(str):
    pass

def literal_presenter(dumper, data):
    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
yaml.add_representer(literal, literal_presenter)

def ordered_dict_presenter(dumper, data):
    return dumper.represent_dict(data.items())
yaml.add_representer(OrderedDict, ordered_dict_presenter)

d = OrderedDict(short=quoted("Hello"), long=literal("Line1\nLine2\nLine3\n"))

print(yaml.dump(d))

出力

short: "Hello"
long: |
  Line1
  Line2
  Line3
于 2011-12-27T06:16:43.553 に答える
13

\nを含む入力はすべてブロックリテラルにしたかったのです。yaml/representer.py私が得たベースとしてのコードを使用して:

# -*- coding: utf-8 -*-
import yaml

def should_use_block(value):
    for c in u"\u000a\u000d\u001c\u001d\u001e\u0085\u2028\u2029":
        if c in value:
            return True
    return False

def my_represent_scalar(self, tag, value, style=None):
    if style is None:
        if should_use_block(value):
             style='|'
        else:
            style = self.default_style

    node = yaml.representer.ScalarNode(tag, value, style=style)
    if self.alias_key is not None:
        self.represented_objects[self.alias_key] = node
    return node


a={'short': "Hello", 'multiline': """Line1
Line2
Line3
""", 'multiline-unicode': u"""Lêne1
Lêne2
Lêne3
"""}

print(yaml.dump(a))
print(yaml.dump(a, allow_unicode=True))
yaml.representer.BaseRepresenter.represent_scalar = my_represent_scalar
print(yaml.dump(a))
print(yaml.dump(a, allow_unicode=True))

出力

{multiline: 'Line1

    Line2

    Line3

    ', multiline-unicode: "L\xEAne1\nL\xEAne2\nL\xEAne3\n", short: Hello}

{multiline: 'Line1

    Line2

    Line3

    ', multiline-unicode: 'Lêne1

    Lêne2

    Lêne3

    ', short: Hello}

After override

multiline: |
  Line1
  Line2
  Line3
multiline-unicode: "L\xEAne1\nL\xEAne2\nL\xEAne3\n"
short: Hello

multiline: |
  Line1
  Line2
  Line3
multiline-unicode: |
  Lêne1
  Lêne2
  Lêne3
short: Hello
于 2013-03-15T01:07:55.537 に答える
7

ruamel.yamlとその RoundTripLoader/Dumper (免責事項: 私はそのパッケージの作成者です) を使用して、必要なことを行う以外に、YAML 1.2 仕様 (2009 年以降) をサポートし、他にもいくつかの改善点があります。

import sys
from ruamel.yaml import YAML

yaml_str = """\
short: "Hello"  # does keep the quotes, but need to tell the loader
long: |
  Line1
  Line2
  Line3
folded: >
  some like
  explicit folding
  of scalars
  for readability
"""

yaml = YAML()
yaml.preserve_quotes = True
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)

与えます:

short: "Hello"  # does keep the quotes, but need to tell the loader
long: |
  Line1
  Line2
  Line3
folded: >
  some like
  explicit folding
  of scalars
  for readability

(前と同じ列から始まるコメントを含む)

この出力を最初から作成することもできますが、その場合は、折り畳む場所の明示的な位置など、追加情報を提供する必要があります。

于 2016-02-15T10:26:04.687 に答える