Вопрос-Ответ

How to fix: "UnicodeDecodeError: 'ascii' codec can't decode byte"

Как исправить: "UnicodeDecodeError: кодек 'ascii' не может декодировать байт"
as3:~/ngokevin-site# nano content/blog/20140114_test-chinese.mkd
as3:~/ngokevin-site# wok
Traceback (most recent call last):
File "/usr/local/bin/wok", line 4, in
Engine()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 104, in init
self.load_pages()
File "/usr/local/lib/python2.7/site-packages/wok/engine.py", line 238, in load_pages
p = Page.from_file(os.path.join(root, f), self.options, self, renderer)
File "/usr/local/lib/python2.7/site-packages/wok/page.py", line 111, in from_file
page.meta['content'] = page.renderer.render(page.original)
File "/usr/local/lib/python2.7/site-packages/wok/renderers.py", line 46, in render
return markdown(plain, Markdown.plugins)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 419, in markdown
return md.convert(text)
File "/usr/local/lib/python2.7/site-packages/markdown/init.py", line 281, in convert
source = unicode(source)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 1: ordinal not in range(128). -- Note: Markdown only accepts unicode input!

Как это исправить?

В некоторых других приложениях для статических блогов на основе python китайская почта может быть успешно опубликована. Например, в этом приложении: http://github.com/vrypan/bucket3. На моем сайте http://bc3.brite.biz / Китайская почта может быть успешно опубликована.

Переведено автоматически
Ответ 1

tl; dr / быстрое исправление


  • Не декодировать волей-неволей

  • Не предполагайте, что ваши строки закодированы в UTF-8

  • Постарайтесь как можно скорее преобразовать строки в Unicode в вашем коде

  • Исправьте вашу локаль: Как решить UnicodeDecodeError в Python 3.6?

  • Не поддавайтесь искушению использовать быстрые reload хаки

Дзен Юникода в Python 2.x - длинная версия

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

UnicodeDecodeError: 'ascii' codec can't decode byte обычно это происходит при попытке преобразовать Python 2.x str, который содержит не ASCII, в строку Unicode без указания кодировки исходной строки.

Вкратце, строки Unicode представляют собой совершенно отдельный тип строк Python, который не содержит никакой кодировки. Они содержат только точечные коды в Юникоде и, следовательно, могут содержать любую точку в Юникоде из всего спектра. Строки содержат закодированный текст, будь то UTF-8, UTF-16, ISO-8895-1, GBK, Big5 и т.д. Строки декодируются в Юникод а юникоды кодируются в строки. Файлы и текстовые данные всегда передаются в закодированных строках.

Авторы модуля Markdown, вероятно, используют unicode() (где генерируется исключение) как контроль качества для остальной части кода - он преобразует ASCII или повторно преобразует существующие строки Unicodes в новую строку Unicode. Авторы Markdown не могут знать кодировку входящей строки, поэтому будут полагаться на вас в декодировании строк в Unicode перед передачей в Markdown.

Строки Unicode могут быть объявлены в вашем коде с помощью u префикса к строкам. Например.

>>> my_u = u'my ünicôdé strįng'
>>> type(my_u)
<type 'unicode'>

Строки Unicode также могут поступать из файлов, баз данных и сетевых модулей. Когда это происходит, вам не нужно беспокоиться о кодировке.

Ошибки

Преобразование из str в Unicode может произойти, даже если вы явно не вызываете unicode().

Следующие сценарии вызывают UnicodeDecodeError исключения:

# Explicit conversion without encoding
unicode('€')

# New style format string into Unicode string
# Python will try to convert value string to Unicode first
u"The currency is: {}".format('€')

# Old style format string into Unicode string
# Python will try to convert value string to Unicode first
u'The currency is: %s' % '€'

# Append string to Unicode
# Python will try to convert string to Unicode first
u'The currency is: ' + '€'

Примеры

На следующей диаграмме вы можете видеть, как слово café было закодировано либо в кодировке "UTF-8", либо в кодировке "Cp1252" в зависимости от типа терминала. В обоих примерах, caf это просто обычный ascii. В UTF-8, é кодируется с использованием двух байтов. В "Cp1252" значение é равно 0xE9 (что также является значением точки в Юникоде (это не совпадение)). Вызвано правильное decode(), и преобразование в Python Unicode успешно выполнено: Схема преобразования строки в строку Python Unicode

На этой диаграмме decode() вызывается с помощью ascii (что аналогично вызову unicode() без заданной кодировки). Поскольку ASCII не может содержать байт больше, чем 0x7F, это вызовет UnicodeDecodeError исключение:

Схема преобразования строки в строку Python Unicode с неправильной кодировкой

Сэндвич с Юникодом

Хорошей практикой является формирование сэндвича с Юникодом в вашем коде, где вы декодируете все входящие данные в строки Юникода, работаете с юникодами, затем кодируете в strs на выходе. Это избавляет вас от беспокойства о кодировании строк в середине вашего кода.

Ввод / декодирование

Исходный код

Если вам нужно вставить в исходный код не ASCII, просто создайте строки в Юникоде, добавив к строке префикс u. Например.

u'Zürich'

Чтобы позволить Python декодировать ваш исходный код, вам нужно будет добавить заголовок encoding, соответствующий фактической кодировке вашего файла. Например, если ваш файл был закодирован как 'UTF-8', вы бы использовали:

# encoding: utf-8

Это необходимо только в том случае, если в вашем исходном коде используется не ASCII.

Файлы

Обычно данные, отличные от ASCII, принимаются из файла. io Модуль предоставляет средство преобразования текста, которое декодирует ваш файл "на лету", используя заданный encoding. Вы должны использовать правильную кодировку для файла - ее нелегко угадать. Например, для файла UTF-8:

import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
my_unicode_string = my_file.read()

my_unicode_string тогда было бы подходящим для передачи в Markdown. Если a UnicodeDecodeError из read() строки, то вы, вероятно, использовали неправильное значение кодировки.

CSV-файлы

Модуль Python 2.7 CSV не поддерживает символы, отличные от ASCII 😩. Однако помощь под рукой с https://pypi.python.org/pypi/backports.csv.

Используйте его, как указано выше, но передайте ему открытый файл:

from backports import csv
import io
with io.open("my_utf8_file.txt", "r", encoding="utf-8") as my_file:
for row in csv.reader(my_file):
yield row

Базы данных

Большинство драйверов баз данных Python могут возвращать данные в Юникоде, но обычно требуют небольшой настройки. Всегда используйте строки Юникода для SQL-запросов.

MySQL

В строке подключения добавить:

charset='utf8',
use_unicode=True

Например.

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")


PostgreSQL

Добавить:

psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
psycopg2.extensions.register_type(psycopg2.extensions.UNICODEARRAY)

HTTP

Веб-страницы могут быть закодированы практически в любой кодировке. Content-type Заголовок должен содержать charset поле, указывающее на кодировку. Затем содержимое может быть декодировано вручную с учетом этого значения. В качестве альтернативы, Python-Requests возвращает Unicodes в response.text.

Вручную

Если вам необходимо декодировать строки вручную, вы можете просто сделать my_string.decode(encoding), где encoding указана соответствующая кодировка. Здесь приведены поддерживаемые кодеки Python 2.x: Стандартные кодировки. Опять же, если вы получитеUnicodeDecodeError, то, вероятно, у вас неправильная кодировка.

Суть сэндвича

Работайте с юникодами так же, как с обычными strs.

Вывод

стандартный вывод / печать

print выполняет запись через поток стандартного вывода. Python пытается настроить кодировщик в стандартном выводе так, чтобы юникоды кодировались в кодировке консоли. Например, если в оболочке Linux locale есть en_GB.UTF-8, выходные данные будут закодированы в UTF-8. В Windows вы будете ограничены 8-битной кодовой страницей.

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

Файлы

Так же, как и input, io.open может использоваться для прозрачного преобразования юникодов в закодированные байтовые строки.

База данных

Та же конфигурация для чтения позволит записывать юникоды напрямую.

Python 3

Python 3 поддерживает Unicode не больше, чем Python 2.x, однако он немного менее запутан в теме. Например, обычный str теперь является строкой Unicode, а старый str теперь bytes.

Кодировкой по умолчанию является UTF-8, поэтому, если вы .decode() вводите байтовую строку без указания кодировки, Python 3 использует кодировку UTF-8. Это, вероятно, устраняет 50% проблем пользователей с Юникодом.

Кроме того, open() по умолчанию работает в текстовом режиме, поэтому возвращает декодированные данные str (в Юникоде). Кодировка является производной от вашей локали, которая, как правило, UTF-8 в системах Un * x или 8-битной кодовой страницы, такой как windows-1251, в окнах Windows.

Почему вы не должны использовать sys.setdefaultencoding('utf8')

Это неприятный взлом (есть причина, по которой вы должны использовать reload), который только замаскирует проблемы и помешает вашему переходу на Python 3.x. Поймите проблему, устраните первопричину и наслаждайтесь дзеном Юникода. Смотрите Почему мы НЕ ДОЛЖНЫ использовать sys.setdefaultencoding("utf-8") в скрипте py? для получения дополнительной информации

Ответ 2

Наконец-то я понял:

as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py
# encoding=utf8
import sys

reload(sys)
sys.setdefaultencoding('utf8')

Позвольте мне проверить:

as3:~/ngokevin-site# python
Python 2.7.6 (default, Dec 6 2013, 14:49:02)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.getdefaultencoding()
'utf8'
>>>

Выше показано, что кодировка python по умолчанию - utf8. Тогда ошибки больше нет.

Ответ 3

Это классическая "проблема с юникодом". Я считаю, что объяснение этого выходит за рамки ответа StackOverflow, чтобы полностью объяснить, что происходит.

Это хорошо объяснено здесь.

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

Презентация, на которую я вам указал, содержит советы, как этого избежать. Сделайте свой код "бутербродом с юникодом". В Python 2 помогает использование from __future__ import unicode_literals.

Обновление: как можно исправить код:

OK - в вашей переменной "source" у вас есть несколько байтов. Из вашего вопроса неясно, как они туда попали - может быть, вы прочитали их из веб-формы? В любом случае, они не кодируются ascii, но python пытается преобразовать их в unicode, предполагая, что это так. Вам нужно явно указать ему, что это за кодировка. Это означает, что вам нужно знать, что это за кодировка! Это не всегда легко, и это полностью зависит от того, откуда взялась эта строка. Вы могли бы поэкспериментировать с некоторыми распространенными кодировками - например, UTF-8. Вы указываете unicode () кодировку в качестве второго параметра:

source = unicode(source, 'utf-8')
Ответ 4

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

import sys
reload(sys)
sys.setdefaultencoding('Cp1252')
2024-01-01 03:23 python python-2.7