Python - "ascii" кодек не може розшифрувати байт


119

Я справді розгублений. Я намагався кодувати, але помилка сказала 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 під кришкою?

Відповіді:


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

encodeперетворює об'єкт unicode в stringоб'єкт. Але тут ви викликали його на stringоб'єкт (тому що у вас немає u). Так пітона повинен перетворити stringв unicodeоб'єкт першим. Так це еквівалент

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

Але декодування виходить з ладу, тому що рядок недійсний ascii. Ось чому ви отримуєте скаргу на те, що не можете розшифрувати.


50
То яке рішення? Особливо, якщо у мене немає літерального рядка, у мене просто об'єкт рядка.
Джон Тірсен

2
@JonTirsen, ви не повинні кодувати рядовий об'єкт. Об'єкт рядка вже закодовано. Якщо вам потрібно змінити кодування, вам потрібно розшифрувати його в рядок unicode, а потім кодувати його як потрібне кодування.
Вінстон Еверт

20
Тож сказати це чітко зверху можна"你好".decode('utf-8').encode('utf-8')
deinonychusaur

5
@WinstonEwert Напевно, я був розгублений. Бізнес, що кодує, як правило, залишає мене вічно розгубленим. Я думаю, що моя плутанина виникла з моєї власної проблеми, коли я не знаю, чи є вхідним рядком або unicode рядком і яке кодування може мати.
deinonychusaur

@deinonychusaur, так ... я розумію.
Вінстон Еверт

53

Завжди кодуйте від 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", важливо зрозуміти, що відбувається на рівні даних. Тут це пояснено іншим способом:

  • Об'єкт unicode вже розшифрований, ви ніколи не хочете його закликати decode.
  • Об'єкт обстеження вже закодований, ви ніколи не хочете його зателефонувати encode.

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

Ці неявні перетворення - це те, чому ви можете отримати, коли вам дзвонили . Це тому, що кодування зазвичай приймає параметр типу ; при отриманні параметра існує неявне декодування в об'єкт типу перед повторним кодуванням його з іншим кодуванням. Ця конверсія вибирає декодер "ascii" за замовчуванням , що дає вам помилку декодування всередині кодера.UnicodeDecodeErrorencodeunicodestrunicode

Насправді в Python 3 методи str.decodeі bytes.encodeнавіть не існують. Їх усунення було [суперечливою] спробою уникнути цієї загальної плутанини.

... або що інше sys.getdefaultencoding()згадує кодування ; зазвичай це "ascii"


Отже, ти маєш на увазі, що Python розшифровує тестування перед кодуванням?
thoslin

@thoslin точно, я додав більше деталей.
Вім

Що таке _, і чому у ваших виписках про друк відсутні дужки?
NoBugs

1
@NoBugs 1. у REPL _посилається на попереднє значення 2. оскільки це питання python-2.x.
Вім

40

Ви можете спробувати це

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

Або

Ви також можете спробувати наступне

Додайте наступний рядок вгорі файлу .py.

# -*- coding: utf-8 -*- 

8

Якщо ви використовуєте 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 .


4
Якщо ви кодуєте рядок, чому вона видає помилку декодування?
MxLDevs

3

Ви використовуєте u"你好".encode('utf8')для кодування рядка unicode. Але якщо ви хочете представити "你好", слід розшифрувати його. Так як:

"你好".decode("utf8")

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


3

Якщо ви маєте справу з Unicode, іноді замість цього encode('utf-8')ви також можете спробувати проігнорувати спеціальні символи, наприклад

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

або як something.decode('unicode_escape').encode('ascii','ignore')запропоновано тут .

Не особливо корисний у цьому прикладі, але може краще працювати в інших сценаріях, коли неможливо перетворити деякі спеціальні символи.

Можна також замінити певний символ використаннямreplace() .


1

Якщо ви запускаєте інтерпретатора 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 (принаймні в деяких випадках, наприклад, у моїй) успадковує кодування оболонки і не зможе друкувати (якісь? Всі?) Символи unicode. Власне кодування 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(або залежно від того, який файл керує визначенням локалі у вашій системі).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.