base64 кодирование строк unicode в python 2.7

у меня есть строка unicode, полученная из веб-службы с помощью requests модуль, который содержит байты двоичного документа (PCL, как это бывает). Один из этих байтов имеет значение 248, и попытка кодирования base64 приводит к следующей ошибке:

In [68]: base64.b64encode(response_dict['content']+'n')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
C:...<ipython-input-68-8c1f1913eb52> in <module>()
----> 1 base64.b64encode(response_dict['content']+'n')

C:Python27Libbase64.pyc in b64encode(s, altchars)
     51     """
     52     # Strip off the trailing newline
---> 53     encoded = binascii.b2a_base64(s)[:-1]
     54     if altchars is not None:
     55         return _translate(encoded, {'+': altchars[0], '/': altchars[1]})

UnicodeEncodeError: 'ascii' codec can't encode character u'xf8' in position 272: ordinal not in range(128)

In [69]: response_dict['content'].encode('base64')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
C:...<ipython-input-69-7fd349f35f04> in <module>()
----> 1 response_dict['content'].encode('base64')

C:...base64_codec.pyc in base64_encode(input, errors)
     22     """
     23     assert errors == 'strict'
---> 24     output = base64.encodestring(input)
     25     return (output, len(input))
     26

C:Python27Libbase64.pyc in encodestring(s)
    313     for i in range(0, len(s), MAXBINSIZE):
    314         chunk = s[i : i + MAXBINSIZE]
--> 315         pieces.append(binascii.b2a_base64(chunk))
    316     return "".join(pieces)
    317

UnicodeEncodeError: 'ascii' codec can't encode character u'xf8' in position 44: ordinal not in range(128)

Я нахожу это немного удивительным, потому что 248 находится в диапазоне беззнакового байта (и может храниться в строке байта), но мой реальный вопрос: что лучше или правильно кодировать эту строку?

моя текущая работа вокруг этого:

In [74]: byte_string = ''.join(map(compose(chr, ord), response_dict['content']))

In [75]: byte_string[272]
Out[75]: 'xf8'

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

5 ответов


поскольку вы работаете с двоичными данными, я не уверен, что это хорошая идея использовать кодировку utf-8. Я думаю, это зависит от того, как вы собираетесь использовать base64 закодированные представления. Я думаю, было бы лучше, если бы вы могли получить данные в виде строки байтов, а не строки unicode. Я никогда не использовал библиотеку запросов, но просмотр документации предполагает, что это возможно. Есть разделы, говорящие о "двоичном содержании ответа"и" необработанном содержании ответа".


у вас unicode строка, которую вы хотите кодировать base64. Проблема в том, что b64encode() работает только на байт, а не символы. Итак, вам нужно преобразовать свой unicode string (которая представляет собой последовательность абстрактных кодовых точек Unicode) в байтовую строку.

отображение абстрактных строк Unicode в конкретный ряд байтов называется кодирование. Python поддерживает несколько кодировок; я предлагаю широко используемый UTF-8 кодировка:

byte_string = response_dict['content'].encode('utf-8')

обратите внимание, что тот, кто декодирует байты, также должен знать, какая кодировка использовалась для возврата unicode строка через комплементарную decode() функция:

# Decode
decoded = byte_string.decode('utf-8')

хорошей отправной точкой для получения дополнительной информации о Unicode и кодировках является Python docs и в этой статье Джоэл Спольски.


Я бы предложил сначала кодировать его на что-то вроде UTF-8 перед кодировкой base64:

In [12]: my_unicode = u'\xf8'

In [13]: my_utf8 = my_unicode.encode('utf-8')

In [15]: base64.b64encode(my_utf8)
Out[15]: 'w7g='

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

эта часть документов называется "Содержание Двоичного Ответа" кажется, идеально подходит для вашей проблемы.


Если это двоичные данные...зачем вообще кодировать / декодировать? Особенно "в base64.encodestring" часть. Ниже показано, как я кодирую изображения в base64 для добавления непосредственно в мой код python вместо дополнительных файлов. 2.7.2 btw

import base64
iconfile = open("blah.icon","rb")
icondata = iconfile.read()
icondata = base64.b64encode(icondata)