在PyYAML中使用表示符时控制折叠位置

问题描述 投票:0回答:1

我能够使用此代码以折叠形式转储具有长字符串的YAML代码:

import yaml

class folded_str(str): pass

def folded_str_representer(dumper, data):
    return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style='>')

yaml.add_representer(folded_str, folded_str_representer)

data = {
    'foo': folded_str(('abcdefghi ' * 10) + 'end\n'),
}

print(yaml.dump(data))

以上代码的输出是:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi end

是否可以控制应在其之后发生折叠的长度?例如,如果我希望行在70个字符后折叠,那么输出将如下所示:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end

有没有办法让PyYAML做到这一点?

python format yaml pyyaml
1个回答
0
投票

控制PyYAML输出的行数的简单方法折叠,是为(全局)行长提供参数width

import sys
import yaml

class folded_str(str): pass

def folded_str_representer(dumper, data):
    return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style='>')

yaml.add_representer(folded_str, folded_str_representer)

data = {
    'foo': folded_str(('abcdefghi ' * 10) + 'end\n'),
}

yaml.dump(data, sys.stdout, width=70)

给出:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end

如您所见,我已删除了对print的呼叫。 PyYAML有一个流界面,并且不直接将其流式传输到输出,因此需要对输出的内存内解释,这既不必要地又慢又容易记忆效率低下。

当然,这也会影响其他任何转储的行(长非折叠标量,流样式列表,深层嵌套的数据结构。

不容易的方法是不调用represent_scalar例程,并且修改PyYAML的ScalarNode(或创建自己的Node类型),然后在发出时在适当的位置输出换行符。


我的ruamel.yaml内置了此功能,以允许此类输出往返保留折叠位置(即使默认输出宽度相同)作为PyYAML)

import sys
import ruamel.yaml

yaml_str = """\
[long, scalar]: "This is just a filler to show that the default width is 80 chars"
foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end
"""

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

给出:

[long, scalar]: This is just a filler to show that the default width is 80 chars
foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end

尽管您可以从头开始创建这样的折叠字符串,但它并不琐碎(没有API,内部表示形式可能会发生变化)。我推荐的是只是创建折叠的字符串数据,然后通过分别定义folded_str来加载它:

import sys
import ruamel.yaml

yaml = ruamel.yaml.YAML()

def folded_str(s, pos=70):
    parts = []
    r = ""
    for part in s.split(' '):
        if not r:
            r = part
        elif len(r) + len(part) >= pos:
            parts.append(r + '\n')
            r = part
        else:
            r += ' ' + part
    parts.append(r)
    return yaml.load(">\n" + "".join(parts))

data = {
    'foo': folded_str(('abcdefghi ' * 10) + 'end\n'),
}

yaml.dump(data, sys.stdout)

给出:

foo: >
  abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi
  abcdefghi abcdefghi abcdefghi end
© www.soinside.com 2019 - 2024. All rights reserved.