首页 > 解决方案 > Yaml Python 2.7 和 Python 3.7 兼容转储和加载 unicode 字符

问题描述

我在使用 PyYaml 加载/转储 yaml 文件时遇到问题,这些文件需要与 Python 2 和 Python 3 兼容。

对于 Python 3 转储/Python 2 加载,我找到了一个解决方案:

import yaml
data = {"d": ""}
with open(file_path, "w") as f:
    yaml.dump(data, f, allow_unicode=True)

这会生成一个带有以下行的 yaml 文件:

d: 

如果我尝试使用 Python 2 加载此文件:

with open(file_path, "r") as f:
    y = yaml.safe_load(f)
    print(y["d"])

我得到以下输出:


但是现在如果我尝试使用 Python 2 转储文件,我尝试了:

data = {"d": u""}
with open(file_name, "w") as f:
   yaml.dump(f)

这会产生一个 yaml 文件:

d: "\uD83D\uDE0B"

我也试过:

data = {"d": u"".encode("utf-8")}
with open(file_name, "w") as f:
   yaml.dump(f)

这会产生一个 yaml 文件:

d: !!python/str "\uD83D\uDE0B"

在这两种情况下,如果我使用 Python 3 加载:

with open(file_path, "r") as f:
    y = yaml.load(f)

then y["d"]is'\ud83d\ude0b' 不能按原样使用。

我发现我可以做类似的事情

y["d"].encode("utf-16", "surrogatepass").decode("utf-16")

但这似乎有点矫枉过正。

那么使用 Python 2 转储一个在 Python 3 中可读且正确解释的文件的解决方案是什么?

标签: pythonpython-2.7python-3.7python-unicodepyyaml

解决方案


我最终为此添加了一个构造函数。我将它添加到自定义加载器中,所以我这样做self.add_constructor了,但在 yaml 级别上是相同的,更容易说明。

yaml.add_constructor("tag:yaml.org,2002:python/str", unicode_constructor)

def unicode_constructor(loader, node):
    scalar = loader.construct_scalar(node)
    return scalar.encode("utf-16", "surrogatepass").decode("utf-16")

这适用于 Python2 转储/Python 3 加载

并且不影响 Python 3 转储/Python 2 或 3 加载


推荐阅读