将locale
库与unicode输入一起使用时,我遇到奇怪的行为。下面是一个最小的工作示例:
>>> x = '\U0010fefd'
>>> ord(x)
1113853
>>> ord('\U0010fefd') == 0X10fefd
True
>>> ord(x) <= 0X10ffff
True
>>> import locale
>>> locale.strxfrm(x)
'\U0010fefd'
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
'en_US.UTF-8'
>>> locale.strxfrm(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: character U+110000 is not in range [U+0000; U+10ffff]
我已经在Python 3.3、3.4和3.5上看到了这一点。我在Python 2.7上没有收到错误。
据我所知,我的unicode输入在适当的unicode范围内,因此似乎在使用'en_US.UTF-8'时
strxfrm
内部的某种方式将输入移出了范围。我正在运行Mac OS X,并且此行为可能与http://bugs.python.org/issue23195有关……但是我给人的印象是,该错误只会表现为错误的结果,而不是引发的异常。我无法在我的SLES 11计算机上进行复制,其他人确认他们无法在Ubuntu,Centos或Windows上进行复制。在注释中听到有关其他操作系统的信息可能会很有帮助。
有人可以解释这可能是什么情况吗?
最佳答案
在Python 3.x中,函数 locale.strxfrm(s)
在内部使用基于当前LC_COLLATE设置的POSIX C函数wcsxfrm()。 POSIX标准以这种方式定义转换:
该定义可以多种方式实现,甚至不需要结果字符串可读。
我创建了一个C代码示例来演示其工作方式:
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main() {
wchar_t buf[10];
wchar_t *in = L"\x10fefd";
int i;
setlocale(LC_COLLATE, "en_US.UTF-8");
printf("in : ");
for(i=0;i<10 && in[i];i++)
printf(" 0x%x", in[i]);
printf("\n");
i = wcsxfrm(buf, in, 10);
printf("out: ");
for(i=0;i<10 && buf[i];i++)
printf(" 0x%x", buf[i]);
printf("\n");
}
它在转换前后打印字符串。
在Linux(Debian Jessie)上运行它的结果是:
in : 0x10fefd
out: 0x1 0x1 0x1 0x1 0x552
在OSX(10.11.1)上运行时,结果是:
in : 0x10fefd
out: 0x103 0x1 0x110000
您可以看到OSX上
wcsxfrm()
的输出包含字符U + 110000,这在Python字符串中是不允许的,因此这是错误的根源。在Python 2.7上,不会引发该错误,因为其
locale.strxfrm()
实现基于strxfrm()
C函数。更新:
进一步研究,我发现OSX上en_US.UTF-8的LC_COLLATE定义是对la_LN.US-ASCII定义的链接。
$ ls -l /usr/share/locale/en_US.UTF-8/LC_COLLATE
lrwxr-xr-x 1 root wheel 28 Oct 1 14:24 /usr/share/locale/en_US.UTF-8/LC_COLLATE -> ../la_LN.US-ASCII/LC_COLLATE
我在Apple的sources中找到了实际的定义。
la_LN.US-ASCII.src
文件的内容如下:order \
\x00;...;\xff
第二次更新:
我已经在OSX上进一步测试了
wcsxfrm()
函数。使用la_LN.US-ASCII整理,给定一系列宽字符C1..Cn
作为输入,输出是具有以下形式的字符串:W1..Wn \x01 U1..Un
在哪里
Wx = 0x103 if Cx > 0xFF else Cx+0x3
Ux = Cx+0x103 if Cx > 0xFF else Cx+0x3
使用此算法
\x10fefd
成为0x103 0x1 0x110000
我已经检查过,并且每个UTF-8语言环境在OSX上都使用此排序规则,因此我倾向于说Apple系统上对UTF-8的排序规则支持已被破坏。所得的排序与通过普通字节比较获得的排序几乎相同,并且具有获得非法Unicode字符的能力。
关于python - 调用locale.strxfrm时Unicode字符不在范围内,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33459384/