我必须读取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
值增加一行新行,然后将其写回,即可生成正确数量的新行。知道我在做什么错吗?
答案 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所示,在折叠样式块标量中保留适当的换行符位置),但从未有人要求这样做,这可能是因为人们是否希望对包装进行这种控制,所以他们以块样式开始。