读写多行字符串的yaml文件

Reading and writing back yaml files with multi-line strings

我必须读取一个 yaml 文件,修改它并使用 pyYAML 写回。一切正常,除非单引号中有多行字符串值,例如如果输入的 yaml 文件看起来像

FOO:
  - Bar: '{"HELLO":
"WORLD"}'

然后将其读取为 data=yaml.load(open("foo.yaml")) 并将其写入 yaml.dump(data, fref, default_flow_style=False) 生成类似

的内容
FOO:
- Bar: '{"HELLO": "WORLD"}'

即没有 Bar 值的额外行。奇怪的是,如果输入文件有类似

FOO:
- Bar: '{"HELLO":

    "WORLD"}'

Bar 值的一个额外的新行然后将其写回会生成正确数量的新行。知道我做错了什么吗?

您没有做错任何事,但您可能应该阅读更多 YAML 规范。

根据 PyYAML 实现的(过时的)1.1 规范,在 single quoted scalars:

In a multi-line single-quoted scalar, line breaks are subject to (flow) line folding, and any trailing white space is excluded from the content.

line-folding

Line folding allows long lines to be broken for readability, while retaining the original semantics of a single long line. When folding is done, any line break ending an empty line is preserved. In addition, any specific line breaks are also preserved, even when ending a non-empty line.

这意味着你的前两个例子是一样的,因为 换行符被读取为好像有 space.

第三个例子不一样,因为它加载后实际上包含一个换行符,因为"any line break ending an empty line is preserved"。 为了理解为什么会在加载时转储,您必须知道 PyYAML 不会 维护有关引用的任何信息(也不是第一个示例中的单个换行符),它 只需将该标量加载到 Python 字符串中。在转储期间 PyYAML 评估该字符串如何 可以最好地编写它考虑的选项(除非你试图使用 dump()default_style 参数来强制事情):普通样式,单引号样式,双引号样式。

PyYAML 将尽可能使用普通样式(不带引号),但由于 字符串以 { 开头,这会导致混淆(冲突) 该角色用作流式映射的开始。所以引用 是必要的。由于字符串中也有双引号,并且 没有需要反斜杠转义 "cleanest" 的字符 PyYAML 可以选择的表示是单引号样式,而在 该样式需要通过包含空值来表示换行符 与单引号标量一致。

我个人更喜欢使用块样式文字标量来表示您的最后一个示例:

FOO:
- Bar: |
  {"HELLO":
    "WORLD"}

但是如果你加载,然后使用 PyYAML 转储它,它的可读性就会丢失。

尽管 YAML 1.2 规范(大约 10 年前发布)中的措辞不同,但行折叠的工作方式相同,因此这将 "work" 以类似的方式使用更新的 YAML loader/dumper。如果您在 YAML() 实例上设置属性 preserve_quotes = True,我的包 ruamel.yaml 用于 loading/dumping YAML 1.2 将正确保持块样式,但它仍然会摆脱换行符在你的第一个例子中。这可以实现(如 ruamel.yaml 在折叠样式块标量中保留适当的换行符位置所示),但从来没有人要求这样做,可能是因为如果人们想要这种对换行的控制,他们会使用块样式来开始与.