Python: 替换 YAML 文件中的字符串

Python: Replacing a String in a YAML file

我有这个示例 YAML 文件:

---
test:
  name: "Tom"
  age: "5"
  version: "1.0"

如何将此 YAML 文件替换为:


test:
  name: "Max"
  age: "10"
  version: "2.2"

这是我打开文件的方式:

import yaml

with open("config.yml", 'r') as stream:
        print(yaml.load(stream))

但是我现在不知道如何编辑 YAML 文件。

鉴于您使用 PyYaml,正确的做法是这样的:

#!/usr/bin/env python

import yaml

with open("testfile.yaml", 'r') as stream:
    try:
        loaded = yaml.load(stream)
    except yaml.YAMLError as exc:
        print(exc)

# Modify the fields from the dict
loaded['test']['name'] = "Max"
loaded['test']['age'] = "10"
loaded['test']['version'] = "2.2"

# Save it again
with open("modified.yaml", 'w') as stream:
    try:
        yaml.dump(loaded, stream, default_flow_style=False)
    except yaml.YAMLError as exc:
        print(exc)

所以你只需将 yaml 加载到一个名为 loadeddict 中,你修改你需要的值然后保存它(覆盖或不覆盖原始文件,你的电话)。对于嵌套输入,您必须修改嵌套字典。 default_flow_style=False 参数是生成所需格式(流样式)所必需的,否则对于嵌套集合,它会生成块样式:

A: a
B: {C: c, D: d, E: e}

干杯!

稍后编辑:

正如 Anthon 所指出的,我的回答有一些缺陷。

  • 最好使用 safe_load 而不是 load 因为后者有潜在的危险。

  • 输出需要一个指令结束指示符(开头的那三个破折号)。为了附加它们,我们在 dump 方法中使用 explicit_start=True(实际上应该是 safe_dump)。

  • 如果你想生成更好的输出(尽管它们在语义上是相同的)

    [=47=,可以使用 ruamel.yaml 而不是 yaml ]

查看 Anthon 的回答以获得更详细的信息,因为他是软件包的作者。

如果你通读 PyYAML 文档,你会发现它 告诉你使用 load() 函数有潜在危险, 所以要做的第一件事(因为你,几乎每个人都没有 需要它),不是使用它,而是使用 safe_load()

您还应该将输入文件更改为 config.yaml, 自 2006 年以来,YAML 文件的 recommended extension 一直是 .yaml

知道了,使用 PyYAML 更改 config.yaml 文件的方法:

import yaml

with open('config.yaml') as stream:
   data = yaml.safe_load(stream)

test = data['test']
test.update(dict(name="Tom", age="10", version="2.2"))

with open('output.yaml', 'wb') as stream:
   yaml.safe_dump(data, stream, default_flow_style=False, 
                  explicit_start=True, allow_unicode=True, encoding='utf-8')

这会给你一个 output.yaml 看起来像:

---
test:
  age: '10'
  name: Tom
  version: '2.2'

default_flow_style 参数是必要的,这样就不会得到 JSON 之类的 叶节点映射的结构。 explicit_start 得到 主要指令结束指示器(---),我建议始终使用 allow_unicode=True, encoding='utf-8'(并以二进制方式打开文件) 以免 运行 在更改 name 时出现意外或问题 至 Björk Guðmundsdóttir.

现在您会注意到,这不会生成您想要的输出 (尽管在语义上相同):

  • 在可以解释为数字的字符串周围使用单引号而不是双引号
  • Tom
  • 周围没有双引号
  • 映射键的排序

如果您在 YAML 文件中有任何评论,这些评论就会丢失。

更新 YAML 文件的更好方法是使用 ruamel.yaml (免责声明:我是那个包的作者),其中有更多 sany 默认值比 PyYAML,处理 YAML 1.2 并且不删除评论 (如果你想把它们放在你的文件中):

import ruamel.yaml


yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.explicit_start = True

with open('config.yaml') as stream:
   data = yaml.load(stream)

test = data['test']
test.update(dict(name="Tom", age="10", version="2.2"))

with open('output.yaml', 'wb') as stream:
    yaml.dump(data, stream)

你的输出文件将是:

---
test:
  name: "Tom"
  age: "10"
  version: "2.2"

这正是您想要的。