调用时Unicode字符不在范围内语言环境.strxfrm

2024-09-28 01:25:23 发布

您现在位置:Python中文网/ 问答频道 /正文

在使用带有unicode输入的locale库时,我遇到了一个奇怪的行为。以下是一个最低限度的工作示例:

>>> 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]

我在python3.3、3.4和3.5上见过这个。我在Python2.7上没有发现错误。在

据我所知,我的unicode输入在适当的unicode范围内,因此在使用'en'时,strxfrm似乎有某种内在的东西_美国UTF-8'表示输入超出范围。在

我正在运行Mac OS X,此行为可能与http://bugs.python.org/issue23195。。。但我的印象是,这个bug只会表现为不正确的结果,而不是引发的异常。我不能在我的sles11机器上复制,其他人确认他们不能在Ubuntu、Centos或Windows上复制。在评论中听到其他操作系统可能会有启发性。在

有人能解释一下引擎盖下面发生了什么吗?在


Tags: inimporttrue示例unicodelocaleutfen
1条回答
网友
1楼 · 发布于 2024-09-28 01:25:23

在python3.x中,函数^{}在内部使用POSIX C函数wcsxfrm(),该函数基于当前的LCˉCOLLATE设置。POSIX标准通过以下方式定义转换:

The transformation shall be such that if wcscmp() is applied to two transformed wide strings, it shall return a value greater than, equal to, or less than 0, corresponding to the result of wcscoll() applied to the same two original wide-character strings.

这个定义可以用多种方式实现,甚至不需要结果字符串是可读的。在

我创建了一个小的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)上运行它的结果是:

^{pr2}$

在OSX(10.11.1)上运行时,结果是:

in : 0x10fefd
out: 0x103 0x1 0x110000

您可以看到OSX上wcsxfrm()的输出包含Python字符串中不允许的字符U+110000,因此这是错误的来源。在

在Python2.7上,不会引发错误,因为它的^{}实现基于strxfrm()C函数。在

更新:

进一步调查,我发现LC峎_美国UTF-OSX上的8是洛杉矶的链接_在美国-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

我在苹果的sources中找到了实际的定义。文件la_LN.US-ASCII.src的内容如下:

order \
    \x00;...;\xff

第二次更新:

我在OSX上进一步测试了wcsxfrm()函数。使用洛杉矶_在美国-ASCII collate,给定一个宽字符序列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变成{}

我已经检查过,并且每个UTF-8语言环境都在OSX上使用这个collate,所以我倾向于说,Apple系统上对UTF-8的collate支持被破坏了。结果的排序与通过普通字节比较获得的顺序几乎相同,但可以获得非法的Unicode字符。在

相关问题 更多 >

    热门问题