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 加载到一个名为 loaded
的 dict
中,你修改你需要的值然后保存它(覆盖或不覆盖原始文件,你的电话)。对于嵌套输入,您必须修改嵌套字典。 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"
这正是您想要的。
我有这个示例 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 加载到一个名为 loaded
的 dict
中,你修改你需要的值然后保存它(覆盖或不覆盖原始文件,你的电话)。对于嵌套输入,您必须修改嵌套字典。 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"
这正是您想要的。