读写多行字符串的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 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 在折叠样式块标量中保留适当的换行符位置所示),但从来没有人要求这样做,可能是因为如果人们想要这种对换行的控制,他们会使用块样式来开始与.
我必须读取一个 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 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 在折叠样式块标量中保留适当的换行符位置所示),但从来没有人要求这样做,可能是因为如果人们想要这种对换行的控制,他们会使用块样式来开始与.