2010-07-01 6 views
8

Я работаю над проектом python в версии 2.6, который также поддерживает будущую поддержку python 3. В частности, я работаю над алгоритмом digest-md5.Python: объединение байтов со строкой

В Python 2.6, не запуская этот импорт:

from __future__ import unicode_literals 

Я могу написать кусок кода, как это:

a1 = hashlib.md5("%s:%s:%s" % (self.username, self.domain, self.password)).digest() 
a1 = "%s:%s:%s" %(a1, challenge["nonce"], cnonce) 

без каких-либо проблем, моя аутентификация работает отлично. Когда я пытаюсь ту же строку кода с unicode_literals импортировала я получаю исключение:

UnicodeDecodeError: «utf8» кодек не может декодировать байт 0xa8 в положении 0: неожиданный байт-код

Теперь я относительно новый на python, поэтому я немного застрял в этом. если я заменю% s в строке форматирования как% r, я могу конкатенировать строку, но аутентификация не работает. Спецификация digest-md5, которую я прочитал, говорит, что 16-разрядный двоичный дайджест должен быть добавлен к этим другим строкам.

Любые мысли?

+1

Python 3.x четко отделяет строки от байт-массивов. В зависимости от ваших потребностей он * может * работать над добавлением шаблонов ''% s:% s:% s "' с 'b' для получения байтового массива, но это может привести к неправильным результатам. Какова цель этого кода? – Philipp

+0

Это фрагмент большого фрагмента кода, который используется для алгоритма digest-md5, который я использую для аутентификации на сервере xmpp, и это конкретный фрагмент кода, вызывающий некоторые проблемы. Предваряющая форматирование строки с b по-прежнему вызывает ту же проблему. Вот еще информация о создании digest-md5 http://web.archive.org/web/20050224191820/http://cataclysm.cx/wip/digest-md5-crash.html – Macdiesel

ответ

5

Причина поведения вы наблюдаемым, что from __future__ import unicode_literals переключает путь Python работает со строками:

  • В 2 .x, строки без префикса u рассматриваются как последовательности байтов, каждый из которых может находиться в диапазоне \ x00- \ xff (включительно). Строки с префиксом u представляют собой кодированные unicode последовательности, кодированные ucs-2.
  • В Python 3.x - так же как в unicode_literals будущем, строка без префикса у является Юникод строки, закодированной в любом UCS-2 или UCS-4 (в зависимости от флага компилятора, используемого при компиляции Python). Строки с префиксом b - это литералы для типа данных bytes, которые скорее похожи на строки, не содержащие unicode до 3.x.

В любой версии Python необходимо преобразовать байт-строки и строки Unicode. Преобразование, выполняемое по умолчанию, зависит от кодировки вашей системы по умолчанию; в вашем случае это UTF-8. Не устанавливая ничего, он должен быть ascii, который отклоняет все символы выше \ x7f.

Сводка сообщений, возвращаемая hashlib.md5 (...). Digest() - это байтовая строка, и я полагаю, что вы хотите, чтобы результат всей операции также был байтовой строкой.Если вы хотите, чтобы конвертировать нонс и cnonce-строку в байты-строк .:

a1 = hashlib.md5("%s:%s:%s" % (self.username, self.domain, self.password)).digest() 
# note that UTF-8 may not be the encoding required by your counterpart, please check 
a1 = b"%s:%s:%s" %(a1, challenge["nonce"].encode("UTF-8"), cnonce.encode("UTF-8")) 

В качестве альтернативы, вы можете преобразовать байтовую строку, идущую от вызова digest() в строку Юникода (не рекомендуется). Поскольку нижний 8 бит UCS-2 эквивалентен ISO-8859-1, это может удовлетворить ваши потребности:

a1 = hashlib.md5("%s:%s:%s" % (self.username, self.domain, self.password)).digest() 
a1 = "%s:%s:%s" %(a1.decode("ISO-8859-1"), challenge["nonce"], cnonce) 
+0

Первое решение, работающее с кодом. Спасибо за ваш проницательный ответ. – Macdiesel

1

Проблема заключается в том, что «% s:% s:% s» стало строкой unicode после импортирования unicode_literals. Выход хэша является «обычной» строкой. Python попытался декодировать обычную строку в строку юникода и не удалось (как и ожидалось. Выход хэша должен выглядеть как шум). Измените код следующим образом:

a1 = a1 + str(':') + str(challenge["nonce"]) + str(':') + str(cnonce) 

Я принимаю cnonce и challenge["nonce"] регулярные строки. Для того, чтобы иметь больше контроля над их преобразования в строки (если требуется), используйте:

a1 += str(':') + challenge["nonce"].encode('UTF-8') + str(':') + cnonce.encode('UTF-8') 
+0

Это решение и объяснение также работает. Спасибо. – Macdiesel

Смежные вопросы