使用PyYaml加载特殊字符

12

我正在编写一个简单的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库无法识别我的表情符号为字符串类型。当我直接将表情符号定义为源代码中的字符串时,我也观察到相同的行为。

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


1
我认为PyYAML根本不支持SMP。 - Ignacio Vazquez-Abrams
1
@IgnacioVazquez-Abrams,抱歉,我不是Unicode专家。SMP是指补充多语言平面吗?SMP是定义表情符号支持的地方吗? - Quinn Stearns
@QuinnStearns SMP是补充的Unicode平面1,该平面包括那些表情符号。PyYAML根据易于修改的测试将它们视为不可打印的。PyYAML的主要开发早在2010年引入表情符号之前就已停止(即在Unicode 6.0及以后),这也是PyYAML不支持最新的YAML 1.2标准(2009)的原因。一个简单的解决方法是重新定义可打印的Unicode字符匹配规则。 - Anthon
2个回答

8

您应该升级到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)。


5

更新

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


原始答案

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

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

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

1
啊哈!太棒了!我为什么没想到呢?谢谢! - Quinn Stearns
1
你并不总是能够控制yaml的内容,对吧? - Peter Kilczuk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接