Кодировка, используемая для u "" литералов - PullRequest
6 голосов
/ 15 января 2012

Рассмотрим следующий пример:

>>> s = u"баба"
>>> s
u'\xe1\xe0\xe1\xe0'
>>> print s
áàáà

Я использую кодирование cp1251 в режиме ожидания, но похоже, что интерпретатор на самом деле использует latin1 для создания строки Unicode:

>>> print s.encode('latin1')
баба

Почему так?Есть ли спецификации для такого поведения?

CPython, 2.7.


Редактировать

Код, который я на самом деле искал, это

>>> u'\xe1\xe0\xe1\xe0' == u'\u00e1\u00e0\u00e1\u00e0'
True

Похоже, что при кодировании Unicode с кодеком latin1 все точки Unicode, меньшие 256, просто остаются как есть, в результате чего получаются байты, которые я набрал ранее.

1 Ответ

8 голосов
/ 16 января 2012

Когда вы вводите символ, такой как б, в терминал, вы видите б, но на самом деле вводится последовательность байтов.

Поскольку кодировка вашего терминала cp1251, ввод баба приводит к последовательности байтов, равной Unicode баба, закодированной в cp1251:

In [219]: "баба".decode('utf-8').encode('cp1251')
Out[219]: '\xe1\xe0\xe1\xe0'

(Обратите внимание, я использую utf-8 выше, потому что моя кодировка терминала utf-8, а не cp1251. Для меня "баба".decode('utf-8') это просто Unicode для баба.)

Поскольку при наборе баба получается последовательность байтов \xe1\xe0\xe1\xe0, когда вы вводите u"баба" в терминал, вместо этого Python получает u'\xe1\xe0\xe1\xe0'. Вот почему вы видите

>>> s
u'\xe1\xe0\xe1\xe0'

Этот юникод представляет áàáà.

А когда вы набираете

>>> print s.encode('latin1')

кодировка latin1 преобразует u'\xe1\xe0\xe1\xe0' в '\xe1\xe0\xe1\xe0'. Терминал получает последовательность байтов '\xe1\xe0\xe1\xe0' и декодирует их с помощью cp1251, таким образом печатая баба:

In [222]: print('\xe1\xe0\xe1\xe0'.decode('cp1251'))
баба

Попытка:

>>> s = "баба"

(без u). Или,

>>> s = "баба".decode('cp1251')

сделать s unicode. Или используйте подробное, но очень явное (и независимое от кодирования терминала ):

>>> s = u'\N{CYRILLIC SMALL LETTER BE}\N{CYRILLIC SMALL LETTER A}\N{CYRILLIC SMALL LETTER BE}\N{CYRILLIC SMALL LETTER A}'

Или короткий, но менее понятный

>>> s = u'\u0431\u0430\u0431\u0430'
...