дополнительные кодовые точки к строке юникода в python - PullRequest
3 голосов
/ 15 февраля 2012

unichr(0x10000) завершается с ValueError, когда cpython компилируется без --enable-unicode=ucs4.

Существует ли встроенная в язык или базовая библиотека функция, которая преобразует произвольное скалярное значение или кодовую точку в юникоде в строку unicode, которая работает независимо от того, на каком интерпретаторе Python работает программа?

1 Ответ

8 голосов
/ 18 ноября 2012

Да, вот, пожалуйста:

>>> unichr(0xd800)+unichr(0xdc00)
u'\U00010000'

Важно понять, что unichr() преобразует целое число в единицу кода в строковом кодировании интерпретатора Python. Документация стандартной библиотеки Python для 2.7.3, 2. Встроенные функции , unichr() читает,

Возвращает строку Unicode один символ , чей код Unicode является целым числом i .... Допустимый диапазон для аргумента зависит от конфигурации Python - это может быть либо UCS2 [0..0xFFFF] или UCS4 [0..0x10FFFF]. ValueError поднимается иначе.

Я добавил акцент на «один символ», под которым они понимают «одну кодовую единицу» в терминах Unicode .

Я предполагаю, что вы используете Python 2.x. Интерпретатор Python 3.x не имеет встроенной функции unichr(). Вместо этого Документация стандартной библиотеки Python для 3.3.0, 2. Встроенные функции , chr() читает,

Возвращает строку , представляющую символ , чья кодовая точка Unicode является целым числом i .... Допустимый диапазон для аргумента - от 0 до 1 114 111 (0x10FFFF в базе 16).

Обратите внимание, что возвращаемое значение теперь является строкой неопределенной длины, а не строкой с одной единицей кода. Таким образом, в Python 3.x chr(0x10000) будет вести себя так, как вы ожидали. Он «преобразует произвольное скалярное значение Юникода или кодовую точку в строку unicode, которая работает независимо от того, на каком интерпретаторе Python работает программа».

Но вернемся к Python 2.x. Если вы используете unichr() для создания объектов Python 2.x unicode и используете скалярные значения Unicode выше 0xFFFF, то вы обязываете свой код знать о реализации интерпретатора Python объектов unicode.

Вы можете изолировать эту осведомленность с помощью функции, которая пытается unichr() по скалярному значению, ловит ValueError и пытается снова с соответствующей суррогатной парой UTF-16:

def unichr_supplemental(scalar):
     try:
         return unichr(scalar)
     except ValueError:
         return unichr( 0xd800 + ((scalar-0x10000)//0x400) ) \
               +unichr( 0xdc00 + ((scalar-0x10000)% 0x400) )

>>> unichr_supplemental(0x41),len(unichr_supplemental(0x41))
(u'A', 1)
>>> unichr_supplemental(0x10000), len(unichr_supplemental(0x10000))
(u'\U00010000', 2)

Но вам может быть проще преобразовать ваши скаляры в 4-байтовые значения UTF-32 в байте UTF-32 string и декодировать этот байт string в строку unicode:

>>> '\x00\x00\x00\x41'.decode('utf-32be'), \
... len('\x00\x00\x00\x41'.decode('utf-32be'))
(u'A', 1)
>>> '\x00\x01\x00\x00'.decode('utf-32be'), \
... len('\x00\x01\x00\x00'.decode('utf-32be'))
(u'\U00010000', 2)

Приведенный выше код был протестирован на Python 2.6.7 с кодировкой UTF-16 для строк Unicode. Я не тестировал его на интерпретаторе Python 2.x с кодировкой UTF-32 для строк Unicode. Однако он должен работать без изменений на любом интерпретаторе Python 2.x с любой реализацией строки Unicode.

...