Кодировать и декодировать строку байтов python

Я пытаюсь преобразовать входящую строку байта, которая содержит символы не-ascii, в допустимую строку utf-8, так что я могу сбросить ее как json.

b = '\x80'
u8 = b.encode('utf-8')
j = json.dumps(u8)

Я ожидал, что j будет '\ xc2\x80', но вместо этого я получаю:

UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0: ordinal not in range(128)

В моей ситуации 'b' поступает из mysql через буферы протокола google и заполняется некоторыми данными blob.

Любые идеи?

EDIT: У меня есть кадры ethernet, которые хранятся в таблице mysql как blob (пожалуйста, все, оставайтесь на теме и не обсудите, почему в таблице есть пакеты). Сопоставление таблицы - utf-8, а слой db (sqlalchemy, non-orm) захватывает данные и создает структуры (буферы протокола google), которые хранят blob как python 'str'. В некоторых случаях я использую протокольные буферы напрямую без каких-либо проблем. В других случаях мне нужно выставить одни и те же данные через json. Я заметил, что когда json.dumps() делает свою вещь, "\ x80" можно заменить недействительным юникодом char (\ ufffd iirc)

Ответ 1

Вам необходимо изучить документацию для API-интерфейса программного обеспечения, которое вы используете. BLOB - это аббревиатура: BINARY Большой объект.

Если ваши данные на самом деле двоичные, идея его декодирования в Unicode - это, конечно, нонсенс.

Если это текст, вам нужно знать, какую кодировку использовать для его декодирования в Unicode.

Затем вы используете json.dumps(a_Python_object)... если вы сами кодируете его в UTF-8, json будет декодировать его снова:

>>> import json
>>> json.dumps(u"\u0100\u0404")
'"\\u0100\\u0404"'
>>> json.dumps(u"\u0100\u0404".encode('utf8'))
'"\\u0100\\u0404"'
>>>

ОБНОВЛЕНИЕ около latin1:

u'\x80' - бесполезный бессмысленный контрольный символ C1 - кодирование крайне маловероятно, чтобы быть латинским-1. Latin-1 - это "ловушка и заблуждение" - все 8-битные байты декодируются в Unicode без привлечения исключения. Не путайте "работы" и "не возбуждайте исключение".

Ответ 2

Используйте b.decode('name of source encoding'), чтобы получить версию юникода. Это было удивительно для меня, когда я это узнал. например:

In [123]: 'foo'.decode('latin-1')
Out[123]: u'foo'

Ответ 3

Я думаю, что вы пытаетесь декорировать строковый объект некоторой кодировки. Вы знаете, что такое кодировка? Чтобы получить объект unicode.

unicode_b = b.decode('some_encoding')

а затем перекодировать объект unicode с использованием кодировки utf_8 обратно в строковый объект.

b = unicode_b.encode('utf_8')

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