Да, здесь вы идете:
>>> unichr(0xd800)+unichr(0xdc00)
u'\U00010000'
Решающий момент, чтобы понять, что unichr()
преобразует целое число в единый блок кода в строках кодирования интерпретатора Python. The Python Standard Library documentation for 2.7.3, 2. Built-in Functions, on unichr()
читает,
Возвращает строку Юникода один символ которого Unicode код является целым числом я .... Допустимый диапазон для аргумента зависит, как Python был настроен - это может быть либо UCS2 [0. .0xFFFF] или UCS4 [0..0x10FFFF]. ValueError
возникает в противном случае.
Я добавил акцент на «один символ», которым они обозначают "one code unit" in Unicode terms.
Я предполагаю, что вы используете Python 2.x. У интерпретатора Python 3.x нет встроенной функции unichr()
. Вместо этого The Python Standard Library documentation for 3.3.0, 2. Built-in Functions, on chr()
читает,
Возвращает строки, представляющая символ которого Юникод элемента кода является целым числом я .... Допустимый диапазон для аргумента от 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 intepreter с кодировкой UTF-32 для строк Unicode. Тем не менее, он должен работать без изменений на любом интерпретаторе Python 2.x с любой реализацией строки Unicode.
Я уверен, что этого не может быть сделано, и что это одна из причин, по которым вы не можете доверять чужому Python для работы на произвольных данных Unicode. Однако это, похоже, исправлено в версии v3.3. Если вам нужен абстрактный Unicode, вам нужно подождать следующей версии или использовать более надежную платформу. – tchrist
@tchrist, спасибо. Да. Мне нужно изучить Python3.x. Кажется, он исправит множество источников путаницы. –
Я (в основном) не согласен с @tchrist, что это невозможно сделать; см. мой ответ ниже, где я это делаю. –