Python - кодек ascii не может декодировать байт
Я действительно смущен. Я пытался кодировать, но ошибка сказала can't decode...
.
>>> "你好".encode("utf8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
Я знаю, как избежать ошибки с префиксом "u" в строке. Мне просто интересно, почему ошибка "не может декодироваться" при вызове encode. Что делает Python под капотом?
Ответы
Ответ 1
"你好".encode('utf-8')
encode
преобразует объект unicode в объект string
. Но здесь вы вызывали его на объект string
(потому что у вас нет u). Таким образом, python должен сначала преобразовать объект string
в объект unicode
. Таким образом, это эквивалентно
"你好".decode().encode('utf-8')
Но декодирование не выполняется, потому что строка недействительна ascii. Вот почему вы получаете жалобу о невозможности декодирования.
Ответ 2
Всегда кодировать из юникода в байты.
В этом направлении вы можете выбрать кодировку.
>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print _
你好
Другой способ - декодировать от байтов до unicode.
В этом направлении вам нужно знать, что кодировка.
>>> bytes = '\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print bytes
你好
>>> bytes.decode('utf-8')
u'\u4f60\u597d'
>>> print _
你好
Эта точка не может быть подчеркнута достаточно. Если вы хотите избежать воспроизведения unicode "whack-a-mole", важно понять, что происходит на уровне данных. Здесь это объясняется по-другому:
- Объект unicode уже декодирован, вы никогда не хотите называть его
decode
.
- Объект bytestring уже закодирован, вы никогда не хотите называть его
encode
.
Теперь, увидев .encode
в байтовой строке, Python 2 сначала пытается неявно преобразовать его в текст (объект unicode
). Аналогично, при просмотре .decode
в строке unicode Python 2 неявно пытается преобразовать его в байты (объект str
).
Эти неявные преобразования - вот почему вы можете получить unicode
decode
Error
, когда вы вызываете encode
. Это потому, что кодировка обычно принимает параметр типа unicode
; при приеме параметра str
существует неявное декодирование в объект типа unicode
перед повторным кодированием его с другим кодированием. Это преобразование выбирает дешифратор "ascii" по умолчанию † что дает вам ошибку декодирования внутри кодера.
Фактически, в Python 3 методы str.decode
и bytes.encode
даже не существуют. Их устранение было [противоречивой] попыткой избежать этой общей путаницы.
†... или что-то вроде кодирования sys.getdefaultencoding()
; обычно это "ascii"
Ответ 3
Вы можете попробовать это
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
или
Вы также можете попробовать
Добавьте следующую строку вверху вашего .py файла.
# -*- coding: utf-8 -*-
Ответ 4
Если вы используете Python < 3, вам нужно сообщить интерпретатору, что ваш строковый литерал является Unicode, префикс его u
:
Python 2.7.2 (default, Jan 14 2012, 23:14:09)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "你好".encode("utf8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
Дальнейшее чтение: Unicode HOWTO.
Ответ 5
Вы используете u"你好".encode('utf8')
для кодирования строки в Юникоде.
Но если вы хотите представить "你好"
, вы должны его декодировать. Также как:
"你好".decode("utf8")
Вы получите то, что хотите. Возможно, вам стоит больше узнать о кодировании и декодировании.
Ответ 6
Если вы имеете дело с Unicode, иногда вместо encode('utf-8')
вы также можете игнорировать специальные символы, например.
"你好".encode('ascii','ignore')
или something.decode('unicode_escape').encode('ascii','ignore')
, как предлагается здесь.
Не особенно полезен в этом примере, но может работать лучше в других сценариях, когда невозможно преобразовать некоторые специальные символы.
В качестве альтернативы вы можете рассмотреть замену определенного символа с помощью replace()
.