Unicode-символ не находится в диапазоне при вызове locale.strxfrm

Я испытываю странное поведение при использовании библиотеки 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.

Насколько я могу судить, мой ввод в Юникоде находится в пределах соответствующего диапазона юникода, поэтому кажется, что что-то внутреннее для strxfrm при использовании «en_US.UTF-8» перемещает вход за пределы диапазона.

Я запускаю Mac OS X, и это поведение может быть связано с http://bugs.python.org/issue23195 … но у меня создалось впечатление, что эта ошибка будет проявляться только как неправильные результаты, а не исключение. Я не могу воспроизвести на своей машине SLES 11, а другие подтверждают, что они не могут реплицироваться на Ubuntu, Centos или Windows. Поучительно слышать о других ОС в комментариях.

Может кто-нибудь объяснить, что может происходить здесь под капотом?

One Solution collect form web for “Unicode-символ не находится в диапазоне при вызове locale.strxfrm”

В Python 3.x функция locale.strxfrm(s) внутренне использует функцию POSIX C wcsxfrm () , которая основана на текущей настройке LC_COLLATE. Стандарт POSIX определяет преобразование следующим образом:

Преобразование должно быть таким, что если wcscmp() применяется к двум преобразованным широким строкам, оно должно возвращать значение, большее или равное или меньшее, чем 0, соответствующее результату wcscoll() примененному к тем же двум оригинальным широкоформатным, символьные строки.

Это определение может быть реализовано несколькими способами и даже не требует, чтобы результирующая строка была читаемой.

Я создал небольшой пример кода 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 

Вы можете видеть, что вывод wcsxfrm() на OSX содержит символ U + 110000, который не разрешен в строке Python, поэтому это является источником ошибки.

В Python 2.7 ошибка не возникает, поскольку ее реализация locale.strxfrm() основана на функции strxfrm() C.

ОБНОВИТЬ:

Исследуя далее, я вижу, что определение LC_COLLATE для en_US.UTF-8 в OSX является ссылкой на определение 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. Содержимое файла la_LN.US-ASCII.src следующее:

 order \ \x00;...;\xff 

2-е ОБНОВЛЕНИЕ:

Я также проверил wcsxfrm() на OSX. Используя сопоставление 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, поэтому я склонен сказать, что поддержка сортировки для UTF-8 в системах Apple нарушена. Результирующий порядок почти совпадает с полученным сравнением с обычным байтом, с бонусом к возможности получения незаконных символов Unicode.

  • Python в чем разница между str (u'a ') и u'a'.encode (' utf-8 ')
  • Замените символы пунктуации полной ширины эквивалентными эквивалентами ширины
  • Кодировка Unicode utf-8 / utf-16 в Python
  • Преобразование строки юникода в строку байта
  • Общая поддержка Unicode / UTF-8 для файлов csv в Python 2.6
  • Python чрезвычайно озадачивает поведение unicode регулярного выражения
  • Уникод Python записывает в файлы сбой в командной строке, но не в IDE
  • UnicodeDecodeError в Python 3 при импорте файла CSV
  • Python - лучший язык программирования в мире.