Python - кодек 'ascii' не может декодировать байт - PullRequest
111 голосов
/ 10 марта 2012

Я действительно запутался.Я пытался закодировать, но ошибка сказала 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» в строке.Мне просто интересно, почему ошибка "не могу декодировать", когда вызывается кодирование.Что Python делает под капотом?

Ответы [ 7 ]

157 голосов
/ 10 марта 2012
"你好".encode('utf-8')

encode преобразует объект Unicode в объект string. Но здесь вы вызвали его на string объекте (потому что у вас нет u). Поэтому python должен сначала преобразовать string в unicode объект. Так что это эквивалентно

"你好".decode().encode('utf-8')

Но декодирование завершается неудачно, потому что строка недопустима ascii. Вот почему вы получаете жалобу на невозможность декодирования.

51 голосов
/ 10 марта 2012

Всегда кодирует из юникода в байты.
В этом направлении вы можете выбрать кодировку .

>>> 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 уже декодирован, вам никогда не нужно вызывать decode для него.
  • Объект строки байтов уже закодирован, вы никогда не захотите вызывать encode для него.

Теперь, увидев .encode в байтовой строке, Python 2 сначала пытается неявно преобразовать ее в текст (объект unicode). Аналогичным образом, при просмотре .decode в строке Unicode Python 2 неявно пытается преобразовать его в байты (объект str).

Эти неявные преобразования - вот почему вы можете получить UnicodeDecodeError, когда вы позвонили encode. Это потому, что кодирование обычно принимает параметр типа unicode; при получении параметра str происходит неявное декодирование в объект типа unicode перед повторным кодированием его другим кодированием. Это преобразование выбирает декодер ascii по умолчанию , что дает вам ошибку декодирования внутри кодера.

На самом деле, в Python 3 методы str.decode и bytes.encode даже не существуют. Их удаление было [противоречивый] попытки избежать этой общей путаницы.

... или любой другой код, упоминаемый sys.getdefaultencoding(); обычно это «ASCII»

39 голосов
/ 04 января 2016

Вы можете попробовать это

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

Или

Вы также можете попробовать следующие действия:

Добавить следующую строку вначало вашего .py файла.

# -*- coding: utf-8 -*- 
8 голосов
/ 10 марта 2012

Если вы используете Python <3, вам нужно сообщить интерпретатору, что ваш строковый литерал <a href="http://docs.python.org/howto/unicode.html#unicode-literals-in-python-source-code" rel="noreferrer"> является 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 .

3 голосов
/ 28 мая 2017

Если вы работаете с Юникодом, иногда вместо encode('utf-8'), вы также можете попытаться игнорировать специальные символы, например

"你好".encode('ascii','ignore')

или как something.decode('unicode_escape').encode('ascii','ignore'), как предлагается здесь.

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

В качестве альтернативы можно рассмотреть замену определенного символаиспользуя replace().

3 голосов
/ 19 декабря 2013

Вы используете u"你好".encode('utf8') для кодирования строки Unicode. Но если вы хотите представить "你好", вы должны декодировать его. Прямо как:

"你好".decode("utf8")

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

0 голосов
/ 28 сентября 2018

Если вы запускаете интерпретатор python из оболочки в Linux или подобных системах (BSD, не уверен в Mac), вам также следует проверить кодировку по умолчанию для оболочки.

Позвоните locale charmap из оболочки (не интерпретатор Python), и вы должны увидеть

[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

Если это не так, и вы видите что-то еще, например

[user@host dir] $ locale charmap
ANSI_X3.4-1968
[user@host dir] $ 

Python будет (по крайней мере, в некоторых случаях, например, в моем) наследовать кодировку оболочки и не сможет печатать (некоторые? Все?) Символы Юникода.Собственная кодировка Python по умолчанию, которую вы видите и контролируете с помощью sys.getdefaultencoding() и sys.setdefaultencoding(), в этом случае игнорируется.

Если вы обнаружите, что у вас есть эта проблема, вы можете исправить ее с помощью

[user@host dir] $ export LC_CTYPE="en_EN.UTF-8"
[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

(Или, альтернативно, выберите любую раскладку клавиш вместо en_EN.) Вы также можете отредактировать /etc/locale.conf (или любой файл, определяющий определение локали в вашей системе), чтобы исправить это.

...