PyYaml - 使用特殊字符(即重音符号)转储 unicode

Posted

技术标签:

【中文标题】PyYaml - 使用特殊字符(即重音符号)转储 unicode【英文标题】:PyYaml - Dump unicode with special characters ( i.e. accents ) 【发布时间】:2015-06-03 06:21:09 【问题描述】:

我正在使用 yaml 文件,这些文件必须是人类可读和可编辑的,但也可以通过 Python 代码进行编辑。 我正在使用 Python 2.7.3

文件需要处理重音符号(主要是处理法语文本)。

这是我的问题的一个示例:

import codecs
import yaml

file = r'toto.txt'

f = codecs.open(file,"w",encoding="utf-8")

text = u'héhéhé, hûhûhû'

textDict = "data": text

f.write( 'write unicode     : ' + text + '\n' )
f.write( 'write dict        : ' + unicode(textDict) + '\n' )
f.write( 'yaml dump unicode : ' + yaml.dump(text))
f.write( 'yaml dump dict    : ' + yaml.dump(textDict))
f.write( 'yaml safe unicode : ' + yaml.safe_dump(text))
f.write( 'yaml safe dict    : ' + yaml.safe_dump(textDict))

f.close()

写入的文件包含:

write unicode     : héhéhé, hûhûhû
write dict        : 'data': u'h\xe9h\xe9h\xe9, h\xfbh\xfbh\xfb\n'

yaml dump unicode : "h\xE9h\xE9h\xE9, h\xFBh\xFBh\xFB"
yaml dump dict    : data: "h\xE9h\xE9h\xE9, h\xFBh\xFBh\xFB"

yaml safe unicode : "h\xE9h\xE9h\xE9, h\xFBh\xFBh\xFB"
yaml safe dict    : data: "h\xE9h\xE9h\xE9, h\xFBh\xFBh\xFB"

yaml 转储非常适合使用 yaml 加载,但它不是人类可读的。

正如您在示例代码中看到的,当我尝试编写 dict 的 unicode 表示时,结果是相同的(我不知道它是否相关)。

我希望转储包含带重音的文本,而不是 unicode 代码。 这可能吗?

【问题讨论】:

这是 Python 2 我猜?我在 Python 2 Unicode 处理方面不太坚定,但您可能想尝试yaml.safe_dump,它以实现中性格式而不是 Python 特定格式转储数据。 哦,是的,对不起,它是 python 2.7.3,使用 safe_dump 有完全相同的输出。 【参考方案1】:

yaml 能够通过向任何转储程序提供 allow_unicode=True 关键字参数来转储 Unicode 字符。如果您不提供文件,您将从dump() 方法返回一个utf-8 字符串(即getvalue() 在为保存转储数据而创建的StringIO() 实例上的结果),您必须在将其附加到您的字符串之前将其转换为utf-8

# coding: utf-8

import codecs
import ruamel.yaml as yaml

file_name = r'toto.txt'

text = u'héhéhé, hûhûhû'

textDict = "data": text

with open(file_name, 'w') as fp:
    yaml.dump(textDict, stream=fp, allow_unicode=True)

print('yaml dump dict 1   : ' + open(file_name).read()),

f = codecs.open(file_name,"w",encoding="utf-8")
f.write('yaml dump dict 2   : ' + yaml.dump(textDict, allow_unicode=True).decode('utf-8'))
f.close()
print(open(file_name).read())

输出:

yaml dump dict 1    : data: 'héhéhé, hûhûhû'
yaml dump dict 2    : data: 'héhéhé, hûhûhû'

我用我的 PyYAML 增强版 (ruamel.yaml) 对此进行了测试,但这在 PyYAML 本身中应该同样有效。

【讨论】:

非常感谢!这完美地工作。我尝试了 allow_unicode 参数,但没有成功(我错过了解码部分)。 亲爱的Anthon,我不知道为什么这个解决方案会给我以下错误:“UnicodeEncodeError: 'charmap' codec can't encode character...”。我使用 Windows 10 英语 + Python 3.6 @ragesz Python3 已经支持 Unicode,如果你使用它,那么不要使用 codecs.open 第一种方法对我有用,但当文本中不存在非 ASCII 字符时,它也会在 YAML 中留下 !!python/unicode 标识符。有没有办法摆脱这些? @Pygmalion 我不确定您要实现什么,使用哪个代码,哪个 python 版本以及在哪个平台上。输出来自实际运行代码(在 Python 2.7 上),因此您必须做一些不同的事情。请发布完整的问题。【参考方案2】:

更新(2020 年)

如今,PyYaml 确实可以轻松地使用 Python 3 处理 unicode,但是这需要 allow_unicode=True 参数:

import yaml
d = 'a': 'héhéhé', 'b': 'hühühü'
yaml_code = yaml.dump(d, allow_unicode=True, sort_keys=False)
print(yaml_code)

将导致:

a: héhéhé
b: hühühü

注意sortkeys=False 参数应从 Python 3.6 开始使用,以保持字典的键不变。 PyYaml 传统上一直对键进行排序,因为 Python 字典没有明确的顺序。即使字典键自 Python 3.6 起就已排序;和officially since 3.7,PyYaml 默认保持排序键。

【讨论】:

以上是关于PyYaml - 使用特殊字符(即重音符号)转储 unicode的主要内容,如果未能解决你的问题,请参考以下文章

XMLHTTP 和特殊字符(例如,重音符号)

使用 PyYaml 加载特殊字符

删除重音和特殊字符[重复]

如何解码 base64 字符串并获取正确的字符,包括重音符号?

如何将重音字符与 PHP preg 匹配?

如何防止写入特殊字符[重复]