【问题标题】:Convert YAML multi-line values to folded block scalar style?将 YAML 多行值转换为折叠块标量样式?
【发布时间】:2016-12-28 00:50:00
【问题描述】:

使用ruamel.yaml,我试图获得某种风格的YAML,更具体地说,单行字符串与:在同一行开始,而多行字符串使用折叠标量风格(|/@ 987654325@) 和行被限制为一定数量的字符(自动换行)。

到目前为止,我的尝试深受similar function called walk_tree in the sources 的影响:

#!/usr/bin/env python

import ruamel.yaml

from ruamel.yaml.scalarstring import ScalarString, PreservedScalarString

def walk_tree(base):
    from ruamel.yaml.compat import string_types

    if isinstance(base, dict):
        for k in base:
            v = base[k]
            if isinstance(v, string_types):
                v = v.replace('\r\n', '\n').replace('\r', '\n').strip()
                base[k] = ScalarString(v) if '\n' in v else v
            else:
                walk_tree(v)
    elif isinstance(base, list):
        for idx, elem in enumerate(base):
            if isinstance(elem, string_types) and '\n' in elem:
                print(elem) # @Anthon: this print is in the original code as well
                base[idx] = preserve_literal(elem)
            else:
                walk_tree(elem)

with open("input.yaml", "r") as fi:
    inp = fi.read()

loader=ruamel.yaml.RoundTripLoader
data = ruamel.yaml.load(inp, loader)

walk_tree(data)

dumper = ruamel.yaml.RoundTripDumper

with open("output.yaml", "w") as fo:
    ruamel.yaml.dump(data, fo, Dumper=dumper, allow_unicode=True)

但是我得到了一个例外:ruamel.yaml.representer.RepresenterError: cannot represent an object: …。如果我将 ScalarString 替换为 PreservedScalarString ,我也不例外

那么如何修复我的代码以使其正常工作?

【问题讨论】:

  • print 的调用将在 0.13.8 中消失,感谢您指出这一点。
  • 如果我的回答不能满足您的需求,请通过将其编辑到您的问题中来包含示例输入(如果不同,则输出)YAML 文件。如果你这样做,你不应该输入 EDIT 。发表简短评论,将触发通知。

标签: python yaml ruamel.yaml


【解决方案1】:

ScalarString 类是LiteralScalarString 的基类,您发现它没有代表。您应该只将其设置/保留为 Python 字符串,因为它可以适当地处理特殊字符(引用需要引用以符合 YAML 规范的字符串)。

假设你有这样的输入:

- 1
- abc: |
    this is a short string scalar with a newline
    in it
- "there are also a multiline\nsequence element\nin this file\nand it is longer"

你可能想做这样的事情:

import ruamel.yaml
from ruamel.yaml.scalarstring import LiteralScalarString, preserve_literal


def walk_tree(base):
    from ruamel.yaml.compat import string_types

    def test_wrap(v):
        v = v.replace('\r\n', '\n').replace('\r', '\n').strip()
        return v if len(v) < 72 else preserve_literal(v)

    if isinstance(base, dict):
        for k in base:
            v = base[k]
            if isinstance(v, string_types) and '\n' in v:
                base[k] = test_wrap(v)
            else:
                walk_tree(v)
    elif isinstance(base, list):
        for idx, elem in enumerate(base):
            if isinstance(elem, string_types) and '\n' in elem:
                base[idx] = test_wrap(elem)
            else:
                walk_tree(elem)

yaml = YAML()

with open("input.yaml", "r") as fi:
    data = yaml.load(fi)

walk_tree(data)

with open("output.yaml", "w") as fo:
    yaml.dump(data, fo)

获取输出:

- 1
- abc: "this is a short string scalar with a newline\nin it"
- |-
  there are also a multiline
  sequence element
  in this file
  and it is longer

一些注意事项:

  • 使用LiteralScalarString 优于PreservedScalarString。后者是唯一保留的字符串类型时的残余名称。
  • 您可能没有 where 字符串的序列元素,因为您没有导入 preserve_literal,尽管它仍在复制的代码中使用。
  • 我将“包装”代码分解到 test_wrap 中,供值和元素包装使用,其最大行长度设置为 72 个字符。
  • data[1]['abc'] 加载为LiteralScalarString。如果您想保留现有的文字样式字符串标量,您应该在测试 string_types 类型之前测试这些标量。
  • 我将新 API 与 YAML() 的实例一起使用
  • 如果您将示例中的 72 增加到默认值 80 以上,您可能必须将 width 属性设置为 1000 之类的值,以防止自动换行。(yaml.width = 1000)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-12
    • 2019-07-09
    • 1970-01-01
    • 2016-05-27
    • 2015-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多