Python YAML 文本的字典不保留字符
Python dict to YAML text doesn't preserve characters
问题很简单,但措辞正确有点棘手。
基本上,我有一个包含以下数据的字典:
x = { foo: [1, '\n', 'bar'] }
当我使用带有 yaml.safe_dump(x, default_flow_style=False)
的 pyyaml 转换为 yaml 时,我希望输出为:
foo:
- 1
- '\n'
- bar
然而,我得到了类似
的东西
foo:
- 1
- '
'
- bar
换行符实际上被解释而不是作为'\n'字符串传递。
我一直在查看 pyyaml 文档,但没有看到正确的咒语来正确解析这个东西。
有没有人以前处理过同样的问题?你是怎么解决的?
为了提供更多背景信息,关于这个。
我有一个json我想转换成yaml。
具有类似内容的文件:
{
"content": {
"Fn::Join": ["\n", [{ "Ref": "parentStackName" }, ""]]
}
}
最终结果应该是这样的:
content:
Fn::Join:
- "\n"
- - Ref: parentStackId
- ''
注意 "\n"
只是一个字符串,而不是实际字符。
我使用的程序是:
- 打开文件
- 从文本到字典解析json
- 使用dict转储到yaml
当我创建字典时,您可以看到“\n”是字符串的一部分。当 pyyaml 将其转储到 yaml 中时,事情就会出错。
要获得所需的输出,您可以使用 ruamel.yaml 的 round-trip 功能,并更新 YAML 的 JSON 子集用来阻止的 flow-style风格:
import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap, CommentedSeq
# because this is a string and not read from file, you need to escape
# the backslash in \n
json_str = """\
{
"content": {
"Fn::Join": ["\n", [{ "Ref": "parentStackName" }, ""]]
}
}
"""
def block_style(base):
"""set all mapping and sequneces to block-style"""
if isinstance(base, CommentedMap):
for k in base:
block_style(base[k])
base.fa.set_block_style()
if isinstance(base, list):
for item in base:
block_style(item)
base.fa.set_block_style()
return base
data = ruamel.yaml.round_trip_load(json_str)
block_style(data)
ruamel.yaml.round_trip_dump(data, sys.stdout)
给出:
content:
Fn::Join:
- "\n"
- - Ref: parentStackName
- ''
ruamel.yaml
是 PyYAML 的更新版本(免责声明:我是作者)。它支持 YAML 1.2 规范(从 2009 年开始),它使 YAML 更符合 JSON 的完整超集,并允许您使用 ruamel.yaml 解析器读取 JSON(PyYAML 仅支持大多数 YAML 1.1 规范)。
在 "round-trip-mode" 中,ruamel.yaml
的增强功能包括保持流程和响应。 block-style 个复合节点(映射和序列)(以及各种引用样式、注释和标签名称)。 block_style()
所做的是递归地将 "flow-attribute" .fa
更改为所有复合节点的块样式。
当字符串包含特殊字符时使用原始字符串:
$ cat /tmp/tmp.py
import yaml
foo = 'foo'
x = { foo: [1, r'\n', 'bar'] }
y = yaml.safe_dump(x, default_flow_style=False)
print(y)
$ python3 /tmp/tmp.py
foo:
- 1
- \n
- bar
问题很简单,但措辞正确有点棘手。
基本上,我有一个包含以下数据的字典:
x = { foo: [1, '\n', 'bar'] }
当我使用带有 yaml.safe_dump(x, default_flow_style=False)
的 pyyaml 转换为 yaml 时,我希望输出为:
foo:
- 1
- '\n'
- bar
然而,我得到了类似
的东西foo:
- 1
- '
'
- bar
换行符实际上被解释而不是作为'\n'字符串传递。
我一直在查看 pyyaml 文档,但没有看到正确的咒语来正确解析这个东西。
有没有人以前处理过同样的问题?你是怎么解决的?
为了提供更多背景信息,关于这个。
我有一个json我想转换成yaml。
具有类似内容的文件:
{
"content": {
"Fn::Join": ["\n", [{ "Ref": "parentStackName" }, ""]]
}
}
最终结果应该是这样的:
content:
Fn::Join:
- "\n"
- - Ref: parentStackId
- ''
注意 "\n"
只是一个字符串,而不是实际字符。
我使用的程序是:
- 打开文件
- 从文本到字典解析json
- 使用dict转储到yaml
当我创建字典时,您可以看到“\n”是字符串的一部分。当 pyyaml 将其转储到 yaml 中时,事情就会出错。
要获得所需的输出,您可以使用 ruamel.yaml 的 round-trip 功能,并更新 YAML 的 JSON 子集用来阻止的 flow-style风格:
import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap, CommentedSeq
# because this is a string and not read from file, you need to escape
# the backslash in \n
json_str = """\
{
"content": {
"Fn::Join": ["\n", [{ "Ref": "parentStackName" }, ""]]
}
}
"""
def block_style(base):
"""set all mapping and sequneces to block-style"""
if isinstance(base, CommentedMap):
for k in base:
block_style(base[k])
base.fa.set_block_style()
if isinstance(base, list):
for item in base:
block_style(item)
base.fa.set_block_style()
return base
data = ruamel.yaml.round_trip_load(json_str)
block_style(data)
ruamel.yaml.round_trip_dump(data, sys.stdout)
给出:
content:
Fn::Join:
- "\n"
- - Ref: parentStackName
- ''
ruamel.yaml
是 PyYAML 的更新版本(免责声明:我是作者)。它支持 YAML 1.2 规范(从 2009 年开始),它使 YAML 更符合 JSON 的完整超集,并允许您使用 ruamel.yaml 解析器读取 JSON(PyYAML 仅支持大多数 YAML 1.1 规范)。
在 "round-trip-mode" 中,ruamel.yaml
的增强功能包括保持流程和响应。 block-style 个复合节点(映射和序列)(以及各种引用样式、注释和标签名称)。 block_style()
所做的是递归地将 "flow-attribute" .fa
更改为所有复合节点的块样式。
当字符串包含特殊字符时使用原始字符串:
$ cat /tmp/tmp.py
import yaml
foo = 'foo'
x = { foo: [1, r'\n', 'bar'] }
y = yaml.safe_dump(x, default_flow_style=False)
print(y)
$ python3 /tmp/tmp.py
foo:
- 1
- \n
- bar