使用 PyYaml 加载特殊字符
Loading special characters with PyYaml
我正在努力在一个简单的 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 文件?
更新
最新版pyyaml修复了这个bug,升级到pyyaml>=5
原回答
这似乎是 pyyaml 中的一个错误,解决方法是使用它们的转义序列:
$ cat test.yaml
- "\U0001f642"
- "\U0001f601"
- "\U0001f62c"
$ python
...
>>> yaml.load(open('test.yaml'))
['', '', '']
你应该升级到 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
).
我正在努力在一个简单的 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 文件?
更新
最新版pyyaml修复了这个bug,升级到pyyaml>=5
原回答
这似乎是 pyyaml 中的一个错误,解决方法是使用它们的转义序列:
$ cat test.yaml
- "\U0001f642"
- "\U0001f601"
- "\U0001f62c"
$ python
...
>>> yaml.load(open('test.yaml'))
['', '', '']
你应该升级到 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
).