Кодировка Python UTF-16 WAVY DASH вопрос / проблема - PullRequest
4 голосов
/ 16 февраля 2010

Сегодня я делал какую-то работу и столкнулся с проблемой, когда что-то "выглядело смешно". Я интерпретировал некоторые строковые данные как utf-8 и проверял закодированную форму. Данные поступали из ldap (в частности, из Active Directory) через python-ldap. Там нет сюрпризов.

Итак, я несколько раз сталкивался с байтовой последовательностью '\ xe3 \ x80 \ xb0', которая при декодировании как utf-8 является кодовой точкой 3030 ( wavy dash ). Мне нужны строковые данные в utf-16, поэтому, естественно, я преобразовал их через .encode ('utf-16'). К сожалению, кажется, что Python не нравится этот персонаж:

D:\> python
Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> u"\u3030"
u'\u3030'
>>> u"\u3030".encode("utf-8")
'\xe3\x80\xb0'
>>> u"\u3030".encode("utf-16-le")
'00'
>>> u"\u3030".encode("utf-16-be")
'00'
>>> '\xe3\x80\xb0'.decode('utf-8')
u'\u3030'
>>> '\xe3\x80\xb0'.decode('utf-8').encode('utf-16')
'\xff\xfe00'
>>> '\xe3\x80\xb0'.decode('utf-8').encode('utf-16-le').decode('utf-8')
u'00'

Кажется, IronPython тоже не фанат:

D:\ipy
IronPython 2.6 Beta 2 (2.6.0.20) on .NET 2.0.50727.3053
Type "help", "copyright", "credits" or "license" for more information.
>>> u"\u3030"
u'\u3030'
>>> u"\u3030".encode('utf-8')
u'\xe3\x80\xb0'
>>> u"\u3030".encode('utf-16-le')
'00'

Если бы кто-нибудь мог сказать мне, что именно здесь происходит, это было бы очень ценно.

Ответы [ 4 ]

2 голосов
/ 16 февраля 2010

Но это хорошо, декодирует:

>>> u"\u3030".encode("utf-16-le")
'00'
>>> '00'.decode("utf-16-le")
u'\u3030'

Дело в том, что кодировка UTF-16 этого символа совпадает с кодом ASCII для «0». Вы также можете представить его с помощью '\ x30 \ x30':

>>> '00' == '\x30\x30'
True
2 голосов
/ 16 февраля 2010

Это похоже на правильное поведение. Символ u '\ u3030' при кодировании в UTF-16 такой же, как кодирование '00' в UTF-8. Это выглядит странно, но это правильно.

'\ xff \ xfe', который вы видите, это просто Порядок следования байтов .

Вы уверены, что хотите волнистую черту, а не какой-нибудь другой персонаж? Если вы надеетесь на другой символ, то это может быть потому, что он уже был неправильно закодирован перед входом в ваше приложение.

1 голос
/ 16 февраля 2010

Вас смущают две вещи здесь (меня тоже сбросили):

  1. Кодировки utf-16 и utf-32 используют спецификацию, если вы не укажете, какой порядок байтов использовать, через utf-16-be и тому подобное. Это \ xff \ xfe во второй последней строке.
  2. '00 '- это два символа цифра ноль . Это не нулевой символ. В любом случае это будет печататься иначе:

    >>> '\0\0'
    '\x00\x00'
    
0 голосов
/ 07 марта 2010

В приведенном выше примере кода есть основная ошибка. Помните, что вы кодируете Unicode в кодированную строку , и вы декодируете из кодированной строки обратно в Unicode. Итак, вы делаете:

'\xe3\x80\xb0'.decode('utf-8').encode('utf-16-le').decode('utf-8')

, что означает следующие шаги:

'\xe3\x80\xb0' # (some string)
.decode('utf-8') # decode above text as UTF-8 encoded text, giving u'\u3030'
.encode('utf-16-le') # encode u'\u3030' as UTF-16-LE, i.e. '00'
.decode('utf-8') # OOPS! decode using the wrong encoding here!

u '\ u3030' действительно кодируется как '00' (ascii zero дважды) в UTF-16LE, но вы почему-то думаете, что это нулевой байт ('\ 0') или что-то в этом роде.

Помните, что вы не можете получить доступ к одному и тому же символу, если кодируете одним и декодируете другим кодированием:

>>> import unicodedata as ud
>>> c= unichr(193)
>>> ud.name(c)
'LATIN CAPITAL LETTER A WITH ACUTE'
>>> ud.name(c.encode("cp1252").decode("cp1253"))
'GREEK CAPITAL LETTER ALPHA'

В этом коде я закодировал в Windows-1252 и декодировал из Windows-1253. В своем коде вы кодировали в UTF-16LE и декодировали из UTF-8.

...