【问题标题】:Reading and writing back yaml files with multi-line strings使用多行字符串读取和写回 yaml 文件
【发布时间】:2019-09-17 01:20:17
【问题描述】:

我必须读取一个 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 multiline pyyaml


    【解决方案1】:

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

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

    在多行单引号标量中,换行符会受到(流)行折叠的影响,并且任何尾随空格都会从内容中排除。

    还有line-folding

    为了便于阅读,行折叠允许对长行进行拆分,同时保留单个长行的原始语义。折叠完成后,任何以空行结尾的换行符都会被保留。此外,任何特定的换行符也会被保留,即使在结束非空行时也是如此。

    这意味着您的前两个示例是相同的,因为 换行符读起来就像有空格一样。

    第三个例子不同,因为它加载后实际上包含一个换行符,因为“任何结束空行的换行符都会被保留”。 为了理解为什么在加载时会转储,您必须知道 PyYAML 不会 维护有关引用的任何信息(也不是第一个示例中的单个换行符),它 只需将该标量加载到 Python 字符串中。在转储 PyYAML 期间评估该字符串的方式 可以最好地编写和它考虑的选项(除非您尝试使用 dump()default_style 参数强制执行某些操作):普通样式、单引号样式、双引号样式。

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

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

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

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

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

    【讨论】:

    • 感谢@Anthon 的详细解释。是的,我应该更详细地阅读规范。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    相关资源
    最近更新 更多