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

问题描述 投票:0回答:2

我有这个示例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文件。

python yaml pyyaml
2个回答
2
投票

鉴于你使用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加载到名为dictloaded中,您可以修改所需的值然后保存它(覆盖原始文件或不覆盖您的调用)。对于嵌套输入,您必须有一个嵌套的dict,您必须修改它。 default_flow_style=False参数是生成所需格式(流样式)所必需的,否则对于嵌套集合,它会生成块样式:

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

干杯!

稍后编辑:

正如安森指出的那样,我的答案有一些缺陷。

  • 最好使用safe_load而不是load,因为后者有潜在危险。
  • 输出需要一个指令结束指示符(开头的那三个破折号)。为了追加它们,我们在explicit_start=True方法中使用dump(实际上应该是safe_dump)。
  • 如果你想产生更好的输出(尽管它们在语义上相同),可以使用ruamel.yaml而不是yaml

请参阅Anthon的答案以获取更详细的信息,因为他是该软件包的作者。


2
投票

如果你仔细阅读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(免责声明:我是该软件包的作者),它有一些比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"

这正是你想要的。

© www.soinside.com 2019 - 2024. All rights reserved.