使用 PyYaml 加载特殊字符

Posted

技术标签:

【中文标题】使用 PyYaml 加载特殊字符【英文标题】:Loading special characters with PyYaml 【发布时间】:2017-12-06 02:56:03 【问题描述】:

我正在努力在一个简单的 python 3.6 脚本中加载表情符号字符列表。 YAML 结构基本如下:

- ????   
- ????
- ????

我的 python 脚本如下所示:

import yaml
f = open('emojis.yml')
EMOJIS = yaml.load(f)
f.close()

我收到以下异常:

yaml.reader.ReaderError: unacceptable character #x001d: special characters are not allowed in "emojis.yml", position 2

我已经看到了allow_unicode=True 选项,但这似乎只适用于 yaml.dump。似乎人们在 Python2 中遇到了类似问题,但由于所有字符串都应该是 unicode,我无法弄清楚为什么这不起作用。

我还尝试将我的表情符号用引号括起来,并为“tag:yaml.org,2002:str”使用客户构造函数。我的自定义构造函数可能从未被击中,因为 yaml lib 无法将我的表情符号识别为字符串类型。当我将表情符号直接定义为源代码中的字符串时,我也会观察到相同的行为。

有没有办法使用 PyYAML 加载包含表情符号的 yaml 文件?

【问题讨论】:

我认为 PyYAML 根本不支持 SMP。 @IgnacioVazquez-Abrams,对不起,没有 unicode 专家。 SMP,你的意思是补充多语言平面吗? SMP 是否定义了表情符号支持? @QuinnStearns SMP 是supplementary Unicode plane 1,该平面包括那些emoticons。 PyYAML 基于易于修改的测试考虑那些不可打印的。 PyYAML 的主要开发在 2010 年推出表情符号之前很久就停止了(即在 Unicode 6.0 及更高版本中),这也是 PyYAML 不支持最新的 YAML 1.2 标准(2009)的原因。一个简单的解决方法是重新定义可打印的 unicode 字符匹配规则。 【参考方案1】:

您应该升级到 ruamel.yaml(免责声明:我是该软件包的作者),它已修复此问题以及许多其他长期存在的 PyYAML 问题:

import sys
from ruamel.yaml import YAML

yaml = YAML()

with open('emojis.yml') as fp:
    idx = 0
    for c in fp.read():
        print(':08x'.format(ord(c)), end=' ')
        idx += 1
        if idx % 4 == 0:
            print()

with open('emojis.yml') as fp:
    data = yaml.load(fp)
yaml.dump(data, sys.stdout)

给予:

0000002d 00000020 0001f642 0000000a 
0000002d 00000020 0001f601 0000000a 
0000002d 00000020 0001f62c 0000000a 
['?', '?', '?']

如果你真的必须坚持使用 PyYAML,你可以这样做:

import yaml.reader
import re

yaml.reader.Reader.NON_PRINTABLE = re.compile(
    u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF]')

摆脱错误。


从版本 0.15.16 开始,ruamel.yaml 现在还转储所有补充平面 Unicode,而不恢复为 \Uxxxxxxxx(可在新 API 中通过 .unicode_supplementary 控制,并取决于 allow_unicode)。子>

【讨论】:

【参考方案2】:

更新

最新版pyyaml已经修复了这个bug,升级到pyyaml>=5


原答案

这似乎是 pyyaml 中的一个错误,解决方法是使用它们的转义序列:

$ cat test.yaml
- "\U0001f642"
- "\U0001f601"
- "\U0001f62c"

$ python
...
>>> yaml.load(open('test.yaml'))
['?', '?', '?']

【讨论】:

啊啊啊太棒了!怎么没想到!?谢谢! 你并不总是可以控制 yaml 的内容,对吧?

以上是关于使用 PyYaml 加载特殊字符的主要内容,如果未能解决你的问题,请参考以下文章

iOS URL带特殊字符(汉字、空格等)导致图片加载失败

重新加载后带有特殊字符的jqGrid过滤器问题

SQL 加载数据特殊字符

URL中出现特殊字符,URL重新加载出现错误

spark sql加载路径中具有特殊字符的parqet

如何使用 Java 将特殊字符插入 MySQL