2012-03-10 5 views
94

Я действительно смущен. Я пытался кодировать, но ошибка указала can't decode....Python - кодек 'ascii' не может декодировать байт

>>> "你好".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 под капотом?

ответ

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

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

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

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

+29

Так в чем же решение? Особенно, если у меня нет строкового литерала, у меня просто есть строковый объект. –

+2

@JonTirsen, вы не должны кодировать строковый объект. Строковый объект уже закодирован. Если вам нужно изменить кодировку, вам необходимо декодировать ее в строку юникода, а затем закодировать ее как нужную кодировку. –

+17

Итак, чтобы четко сформулировать это, вы можете '' 你好 ".decode ('utf-8'). Encode ('utf-8')' – deinonychusaur

44

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

>>> 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», важно понять, что происходит на уровне данных. Здесь объясняется еще один способ:

  • Юникодный объект уже декодирован, вы никогда не хотите называть его decode.
  • Объект bytestring уже закодирован, вы никогда не хотите называть его encode.

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

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

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

... или иное кодирование sys.getdefaultencoding() упоминает; как правило, это 'ASCII'

+0

Итак, вы имеете в виду, что Python декодирует байтовое кодирование перед кодированием? – thoslin

+0

@thoslin точно, я добавил более подробную информацию. – wim

+0

Что такое _, и почему ваши заявления о печати отсутствуют скобки? – NoBugs

6

Если вы используете Python < 3, вам необходимо сообщить интерпретатору, что ваш string literal is Unicode by prefixing it with a 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

Если вы кодируете строку, почему она генерирует ошибку декодирования? – MxyL

1

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

"你好".decode("utf8") 

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

33

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

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

Или

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

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

# -*- coding: utf-8 -*- 
+5

Мессинг с кодировкой из Python, если это возможно, является действительно опасной идеей. Вы * будете * вызывать непредвиденные проблемы, если вы это сделаете. Вместо этого верните свои данные, как описано в других ответах. – davidism

+1

@ давидизм - почему/как? – Xodarap777

1

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

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

или как something.decode('unicode_escape').encode('ascii','ignore') as suggested here.

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

В качестве альтернативы вы можете рассмотреть replacing particular character using replace().