我必须读取yaml文件,修改它并使用pyYAML回写。除非单引号中有多行字符串值,否则每件事都可以正常工作,例如如果输入yaml文件看起来像
FOO:
- Bar: '{"HELLO":
"WORLD"}'
然后读它作为qazxsw poi并写它qazxsw poi生成类似的东西
data=yaml.load(open("foo.yaml"))
即没有额外的yaml.dump(data, fref, default_flow_style=False)
值。奇怪的是,如果输入文件有类似的东西
FOO:
- Bar: '{"HELLO": "WORLD"}'
即为Bar
值增加一条新线,然后将其写回,生成正确数量的新线。知道我做错了什么吗?
你没有做错任何事,但你可能应该阅读更多的YAML规范。
根据PyYAML实现的(过时的)1.1规范,在FOO:
- Bar: '{"HELLO":
"WORLD"}'
中:
在多行单引号标量中,换行符受(流)行折叠,并且从内容中排除任何尾随空格。
和Bar
:
线折叠允许打破长线以便于阅读,同时保留单条长线的原始语义。折叠完成后,将保留任何以空行结尾的换行符。此外,即使在结束非空行时,也会保留任何特定的换行符。
这意味着前两个示例是相同的,因为读取换行符就好像有空格一样。
第三个例子是不同的,因为它在加载后实际上包含一个换行符,因为“保留任何以空行结尾的换行符”。为了理解在加载时转储的原因,你必须知道PyYAML没有维护有关引用的任何信息(也没有关于第一个例子中的单个换行符),它只是将该标量加载到Python字符串中。在转储期间,PyYAML会评估如何最好地编写该字符串以及它所考虑的选项(除非您尝试使用single quoted scalars参数强制使用line-folding):简单样式,单引号样式,双引号样式。
PyYAML将尽可能使用普通样式(不带引号),但由于字符串以default_style
开头,这会导致混淆(碰撞)该字符用作流样式映射的开始。因此引用是必要的。由于字符串中也有双引号,并且没有字符需要反斜杠转义PyYAML可以选择的“最干净”表示是单引号样式,并且在该样式中它需要通过包含emtpy行来表示换行符用单引号标量。
我个人更喜欢使用块样式文字标量来表示你的最后一个例子:
dump()
但如果你加载,然后使用PyYAML转储它的可读性将丢失。
尽管在YAML 1.2规范(近10年前发布)中措辞不同,但折线的工作方式相同,因此这将与更新的YAML装载器/倾卸器以类似的方式“工作”。我的包ruamel.yaml,用于加载/转储YAML 1.2将正确维护块样式,如果你在{
实例上设置属性FOO:
- Bar: |
{"HELLO":
"WORLD"}
,但它仍将摆脱你的第一个例子中的换行符。这可以实现(如ruamel.yaml在折叠样式块标量中保留适当的换行位置所示),但没有人曾经要求过,可能是因为如果人们想要对包装进行那种控制,他们会使用块样式开始。