gpt4 book ai didi

python - 调用 locale.strxfrm 时 Unicode 字符不在范围内

转载 作者:太空狗 更新时间:2023-10-29 20:58:29 24 4
gpt4 key购买 nike

当使用带有 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]

我在 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)内部使用 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) 上运行,结果如下:

in : 0x10fefd
out: 0x1 0x1 0x1 0x1 0x552

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

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

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

在 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

我在 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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com