Преобразование Python - Unicode в ASCII

Я не могу преобразовать следующий Unicode в ASCII без потери данных:

u'ABRA\xc3O JOS\xc9'

Я пробовал encode и decode, и они этого не сделают.

Есть ли у кого-нибудь предложение?

Ответ 1

Символы Unicode u'\xce0' и u'\xc9' не имеют соответствующих значений ASCII. Поэтому, если вы не хотите потерять данные, вам необходимо закодировать эти данные так, чтобы они были действительны как ASCII. Варианты включают:

>>> print s.encode('ascii', errors='backslashreplace')
ABRA\xc3O JOS\xc9
>>> print s.encode('ascii', errors='xmlcharrefreplace')
ABRAÃO JOSÉ
>>> print s.encode('unicode-escape')
ABRA\xc3O JOS\xc9
>>> print s.encode('punycode')
ABRAO JOS-jta5e

Все это строки ASCII и содержат всю информацию из исходной строки Unicode (так что все они могут быть отменены без потери данных), но ни один из них не подходит для конечного пользователя (и ни один из них можно обратить вспять только на decode('ascii')).

См. str.encode, Специфические кодовые обозначения на Python, и Unicode HOWTO для получения дополнительной информации.


В качестве побочного примечания, когда некоторые люди говорят "ASCII", они действительно не означают "ASCII", а скорее "любой 8-битный набор символов, который является надмножеством ASCII" или "некоторым определенным 8-битным набором символов, который Я имею в виду". Если это то, что вы имели в виду, решение состоит в кодировании в правый 8-битный набор символов:

>>> s.encode('utf-8')
'ABRA\xc3\x83O JOS\xc3\x89'
>>> s.encode('cp1252')
'ABRA\xc3O JOS\xc9'
>>> s.encode('iso-8859-15')
'ABRA\xc3O JOS\xc9'

Жесткая часть - это знать, какой набор символов вы имели в виду. Если вы пишете и код, который производит 8-битные строки, и код, который его использует, и вы не знаете ничего лучше, вы имели в виду UTF-8. Если код, который потребляет 8-битные строки, это, скажем, функция open или веб-браузер, который вы обслуживаете страницу, или что-то еще, все сложнее, и нет простого ответа без дополнительной информации.

Ответ 2

Мне нужно было вычислить MD5 hash для unicode string, полученного в HTTP request. MD5 давал UnicodeEncodeError, а встроенные методы кодирования python не работали, потому что он заменял символы в строке соответствующими hex values для символов, таким образом изменяя MD5 hash. Итак, я придумал следующий код, который сохраняет строку без изменений при конвертации из unicode.

unicode_string = ''.join([chr(ord(x)) for x in unicode_string]).strip()

Это удаляет часть unicode из строки и сохраняет все данные без изменений.