使用多行字符串读写Yaml文件

时间:2019-04-28 00:36:18

标签: yaml multiline pyyaml

我必须读取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值增加一行新行,然后将其写回,即可生成正确数量的新行。知道我在做什么错吗?

1 个答案:

答案 0 :(得分:0)

您没有做错任何事情,但是您可能应该阅读更多有关YAML规范的信息。

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

  

在多行单引号标量中,换行符受(流动)行折叠的约束,任何尾随空格均从内容中排除。

还有line-folding

  

行折叠允许将长行折断以提高可读性,同时保留单个长行的原始语义。折叠完成后,将保留以空行结尾的任何换行符。此外,即使结束非空行,也会保留所有特定的换行符。

这意味着您的前两个示例与 读取换行符就好像有一个空格。

第三个示例有所不同,因为它实际上在加载后包含换行符,因为“保留了以空行结尾的任何换行符”。 为了了解为什么在加载时会转回,您必须知道PyYAML不会 维护有关报价的所有信息(在第一个示例中也不涉及单个换行符), 只是将标量加载到Python字符串中。在转储期间,PyYAML评估该字符串的方式 最好编写并考虑它的选项(除非您尝试使用default_style的{​​{1}}参数来强制执行操作):纯样式,单引号样式,双引号样式。

PyYAML将在可能的情况下使用纯格式(不带引号),但是由于 字符串以dump()开头,这会导致与 该角色用作流程样式映射的开始。所以引用 是必要的。由于字符串中也有双引号,并且 没有需要反斜杠转义“最干净”字符的字符 PyYAML可以选择的表示形式是单引号样式,并且在 该样式需要通过包含空字符来表示换行 与单引号标量对齐。

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

{

但是如果您加载,然后使用PyYAML转储该文件,则其可读性将丢失。

尽管在YAML 1.2规范(将近10年前发布)中措辞有所不同,但行折叠的工作原理相同,因此,这对于更新的YAML加载程序/转储程序将以类似的方式“起作用”。如果您在FOO: - Bar: | {"HELLO": "WORLD"} 实例上设置属性preserve_quotes = True,则用于加载/转储YAML 1.2的我的包ruamel.yaml将正确维护块样式,但是在第一个示例中,它仍将摆脱换行符。可以实现这一点(如ruamel.yaml所示,在折叠样式块标量中保留适当的换行符位置),但从未有人要求这样做,这可能是因为人们是否希望对包装进行这种控制,所以他们以块样式开始。