Python 如何控制PyYAML对数据使用的标量形式?

Python 如何控制PyYAML对数据使用的标量形式?,python,yaml,pyyaml,Python,Yaml,Pyyaml,我有一个具有短字符串属性和长多行字符串属性的对象。我想将短字符串写为YAML引号标量,将多行字符串写为文字标量: my_obj.short = "Hello" my_obj.long = "Line1\nLine2\nLine3" 我希望YAML看起来像这样: short: "Hello" long: | Line1 Line2 Line3 我怎样才能指示Pyaml这样做?如果我调用yaml.dump(my_obj),它会产生类似dict的输出: {long: 'line1

我有一个具有短字符串属性和长多行字符串属性的对象。我想将短字符串写为YAML引号标量,将多行字符串写为文字标量:

my_obj.short = "Hello"
my_obj.long = "Line1\nLine2\nLine3"
我希望YAML看起来像这样:

short: "Hello"
long: |
  Line1
  Line2
  Line3
我怎样才能指示Pyaml这样做?如果我调用
yaml.dump(my_obj)
,它会产生类似dict的输出:

{long: 'line1

    line2

    line3

    ', short: Hello}
(不知道为什么长是双倍间隔的…)

我能告诉皮亚姆如何对待我的属性吗?我想影响订单和款式。

基于

输出
我希望任何带有
\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
爱上了,我得到了这个密码:

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)
它使每个多行字符串都是块文字

我试图避免猴子修补的部分。 完全归功于@lbt和@J.F.Sebastian。

您可以使用其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
(包括注释,从前面的同一列开始)

您也可以从头开始创建此输出,但是
确实需要提供额外信息,例如折叠位置的明确位置。

这是一种很好的方法,可以避免显式标记输入字符串。您可以使用
is_multiline=lambda s:len(s.splitlines())>1
自动识别Unicode换行符,并且对于一行不会返回true。@J.F.Sebastian很高兴看到这个漂亮的技巧。现在代码看起来好多了。非常感谢!嗯,
风格=“|”
似乎没有影响pyyaml@jfs是的,但是pyyaml发射器将在两行上打印
test\n
,并用单引号括起来,因此,如果此练习的目标是在字符串包含换行符时使用块样式而不是引号,那么我们必须像处理多行一样处理这种情况(无论这在技术上是否正确)。与其使用
拆分行
,不如简单地测试
数据中的'\n'是否更便宜,并做同样的事情。是否可以这样做,使其不会影响全局yaml状态,但会影响对
转储()的单个调用
?@JasonS:这是一个很好的单独问题。您可以尝试使用重写的表示标量、表示dict方法将自己的转储程序类传递给
yaml.dump
。由于某些原因,这在本例中不起作用:。有什么想法吗?这是一个很好的答案,非常适合我,谢谢!…但我想补充一点,这适用于
yaml.dump()
但不适用于
yaml.safe\u dump()
。除非有办法让它适用于我错过的
yaml.safe\u dump()
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