Как исправить: "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 успешно выполнено:
На этой диаграмме decode()
вызывается с помощью ascii
(что аналогично вызову unicode()
без заданной кодировки). Поскольку ASCII не может содержать байт больше, чем 0x7F
, это вызовет UnicodeDecodeError
исключение:
Сэндвич с Юникодом
Хорошей практикой является формирование сэндвича с Юникодом в вашем коде, где вы декодируете все входящие данные в строки Юникода, работаете с юникодами, затем кодируете в str
s на выходе. Это избавляет вас от беспокойства о кодировании строк в середине вашего кода.
Ввод / декодирование
Исходный код
Если вам нужно вставить в исходный код не 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')