Python字典对YAML文本不保留字符

时间:2017-01-23 22:05:24

标签: python dictionary yaml pyyaml

问题很简单,但要正确说出来有点棘手。

基本上,我有一本包含以下数据的字典:

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"只是一个字符串,而不是实际字符。

我正在使用的程序是:

  1. 打开文件
  2. 将json从文本解析为dict
  3. 使用dict转储到yaml
  4. 当我创建dict时,您可以看到“\ n”作为字符串的一部分。当pyyaml将其转移到yaml中时,事情就会出错。

2 个答案:

答案 0 :(得分:2)

要获得所需的输出,您可以使用ruamel.yaml的往返功能,并更新YAML的JSON子集用于阻止样式的流式:

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规范)。

在“往返模式”中,ruamel.yaml的增强功能包括保持流量。单个基础上的复合节点(映射和序列)的块样式(以及各种引用样式,注释和标记名称)。 block_style()的作用是递归地将“flow-attribute”.fa更改为所有复合节点的块样式。

答案 1 :(得分:-1)

当字符串包含特殊字符时,请使用原始字符串

$ 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