Как исправить: "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/quick fix

  • Не декодируйте/не кодируйте Вилли Нилли
  • Не думайте, что ваши строки имеют кодировку UTF-8
  • Попробуйте преобразовать строки в строки Unicode как можно скорее в своем коде
  • Исправьте язык: Как решить UnicodeDecodeError в Python 3.6?
  • Не поддавайтесь искушению использовать быстрые reload хаки

Unicode Zen в Python 2.x - длинная версия

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

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

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

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

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

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

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

Gotchas

Преобразование из 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 (что также является значением точки Unicode (это не совпадение)). Правильный decode() вызывается, и преобразование в Юникод Python успешно: Diagram of a string being converted to a Python Unicode string

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

Diagram of a string being converted to a Python Unicode string with the wrong encoding

Бутерброд с Юникодом

Рекомендуется формировать сэндвич Unicode в вашем коде, где вы декодируете все входящие данные в строки Unicode, работаете с Unicodes, а затем кодируете в str. Это избавит вас от беспокойства по поводу кодирования строк в середине вашего кода.

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

Исходный код

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

u'Zürich'

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

# encoding: utf-8

Это необходимо, только если в вашем исходном коде есть код, отличный от ASCII.

файлы

Обычно не-ASCII данные получаются из файла. Модуль io предоставляет TextWrapper, который декодирует ваш файл на лету, используя заданный 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. Если 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 могут возвращать данные в Unicode, но обычно требуют небольшой настройки. Всегда используйте строки Unicode для запросов 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 возвращает юникоды в response.text.

вручную

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

Мясо бутерброда

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

Выход

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

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

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

файлы

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

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

Python 3

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

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

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

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

Это неприятный хак (есть причина, по которой вы должны использовать reload), который только маскирует проблемы и мешает переходу на Python 3.x. Разберитесь в проблеме, устраните причину и наслаждайтесь Unicode ZEN. Смотрите Почему бы нам НЕ использовать 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

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

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

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

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

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

ОК - в вашей переменной "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')

Ответ 5

Я искал решение следующего сообщения об ошибке:

unicodedecodeerror: кодек "ascii" не может декодировать байт 0xe2 в позиции 5454: порядковый номер не в диапазоне (128)

Я, наконец, исправился, указав "кодирование":

f = open('../glove/glove.6B.100d.txt', encoding="utf-8")

Хотелось бы, чтобы это тоже помогло вам.

Ответ 6

"UnicodeDecodeError: 'ascii' codec can't decode byte"

Причина этой ошибки: input_string должен быть unicode, но str дано

"TypeError: Decoding Unicode is not supported"

Причина этой ошибки: попытка конвертировать unicode input_string в unicode


Поэтому сначала проверьте, что ваш input_string является str и конвертируется в unicode, если необходимо:

if isinstance(input_string, str):
   input_string = unicode(input_string, 'utf-8')

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

if isinstance(input_string, str):
   input_string = input_string.decode('ascii', 'ignore').encode('ascii') #note: this removes the character and encodes back to string.

elif isinstance(input_string, unicode):
   input_string = input_string.encode('ascii', 'ignore')

Ответ 7

Я считаю, что лучше всего всегда конвертировать в unicode, но этого трудно достичь, потому что на практике вам нужно будет проверять и преобразовывать каждый аргумент в каждую функцию и метод, которые вы когда-либо пишете, включая некоторую форму обработки строк.

Итак, я придумал следующий подход, чтобы либо гарантировать unicodes, либо строки байтов, либо с любого ввода. Короче говоря, включает и использует следующие lambdas:

# guarantee unicode string
_u = lambda t: t.decode('UTF-8', 'replace') if isinstance(t, str) else t
_uu = lambda *tt: tuple(_u(t) for t in tt) 
# guarantee byte string in UTF8 encoding
_u8 = lambda t: t.encode('UTF-8', 'replace') if isinstance(t, unicode) else t
_uu8 = lambda *tt: tuple(_u8(t) for t in tt)

Примеры:

text='Some string with codes > 127, like Zürich'
utext=u'Some string with codes > 127, like Zürich'
print "==> with _u, _uu"
print _u(text), type(_u(text))
print _u(utext), type(_u(utext))
print _uu(text, utext), type(_uu(text, utext))
print "==> with u8, uu8"
print _u8(text), type(_u8(text))
print _u8(utext), type(_u8(utext))
print _uu8(text, utext), type(_uu8(text, utext))
# with % formatting, always use _u() and _uu()
print "Some unknown input %s" % _u(text)
print "Multiple inputs %s, %s" % _uu(text, text)
# but with string.format be sure to always work with unicode strings
print u"Also works with formats: {}".format(_u(text))
print u"Also works with formats: {},{}".format(*_uu(text, text))
# ... or use _u8 and _uu8, because string.format expects byte strings
print "Also works with formats: {}".format(_u8(text))
print "Also works with formats: {},{}".format(*_uu8(text, text))

Вот еще несколько рассуждений об этом.

Ответ 8

Кодирование преобразует объект unicode в строковый объект. Я думаю, вы пытаетесь закодировать строковый объект. сначала конвертируйте свой результат в объект unicode, а затем закодируйте этот объект unicode в "utf-8". например

    result = yourFunction()
    result.decode().encode('utf-8')

Ответ 9

Чтобы решить эту проблему на уровне операционной системы в установке Ubuntu, проверьте следующее:

$ locale charmap

Если вы получаете

locale: Cannot set LC_CTYPE to default locale: No such file or directory

вместо

UTF-8

затем установите LC_CTYPE и LC_ALL следующим образом:

$ export LC_ALL="en_US.UTF-8"
$ export LC_CTYPE="en_US.UTF-8"

Ответ 10

У меня была такая же проблема, но она не работала для Python 3. Я последовал этому, и она решила мою проблему:

enc = sys.getdefaultencoding()
file = open(menu, "r", encoding = enc)

Вы должны установить кодировку, когда будете читать/записывать файл.

Ответ 11

У меня такая же проблема со строкой "PastelerÃa Mallorca", и я решил с помощью:

unicode("Pastelería Mallorca", 'latin-1')

Ответ 12

Короче говоря, чтобы обеспечить правильную обработку Юникода в Python 2:

  • использовать io.open для чтения/записи файлов
  • использовать from __future__ import unicode_literals
  • настроить другие входы/выходы данных (например, базы данных, сеть) для использования unicode
  • если вы не можете настроить выходы на utf-8, конвертируйте свой вывод для них print(text.encode('ascii', 'replace').decode())

Для пояснений см. Подробный ответ @Alastair McCormack.

Ответ 13

У меня была та же ошибка, с URL, содержащими символы не ascii (байты со значениями> 128), мое решение:

url = url.decode('utf8').encode('utf-8')

Примечание: utf-8, utf8 - это просто псевдонимы. Использование только utf8 или utf-8 должно работать одинаково

В моем случае, работавшем для меня, в Python 2.7, я предполагаю, что это назначение изменило "что-то" во внутреннем представлении str - то есть, оно вызывает правильное декодирование последовательности байтов в url и, наконец, помещает строку в UTF-8 str со всей магией в нужном месте. Unicode в Python для меня черная магия. Надеюсь, полезно

Ответ 14

Это сработало для меня:

    file = open('docs/my_messy_doc.pdf', 'rb')

Ответ 15

В проекте Django (1.9.10)/Python 2.7.5 у меня есть частые исключения UnicodeDecodeError; в основном, когда я пытаюсь передать строки Unicode для ведения журнала. Я сделал вспомогательную функцию для произвольных объектов, чтобы в основном форматировать 8-битные строки ascii и заменять любые символы, не входящие в таблицу, на "?". Я думаю, что это не лучшее решение, но поскольку кодировка по умолчанию - ascii (и я не хочу ее менять), она будет делать:

def encode_for_logging(c, encoding='ascii'):
    if isinstance(c, basestring):
        return c.encode(encoding, 'replace')
    elif isinstance(c, Iterable):
        c_ = []
        for v in c:
            c_.append(encode_for_logging(v, encoding))
        return c_
    else:
        return encode_for_logging(unicode(c))
`

Ответ 16

Эта ошибка возникает, когда в нашей строке присутствуют некоторые символы не ASCII, и мы выполняем любые операции над этой строкой без надлежащего декодирования. Это помогло мне решить мою проблему. Я читаю CSV файл с идентификаторами столбцов, текстами и декодированием в нем, как показано ниже:

train_df = pd.read_csv("Example.csv")
train_data = train_df.values
for i in train_data:
    print("ID :" + i[0])
    text = i[1].decode("utf-8",errors="ignore").strip().lower()
    print("Text: " + text)

Ответ 17

Вот мое решение, просто добавьте кодировку. with open(file, encoding='utf8') as f

И поскольку чтение перчаточного файла займет много времени, я рекомендую файл перчаток в файл numpy. Когда netx вы прочтете весы внедрения, это сэкономит ваше время.

import numpy as np
from tqdm import tqdm


def load_glove(file):
    """Loads GloVe vectors in numpy array.
    Args:
        file (str): a path to a glove file.
    Return:
        dict: a dict of numpy arrays.
    """
    embeddings_index = {}
    with open(file, encoding='utf8') as f:
        for i, line in tqdm(enumerate(f)):
            values = line.split()
            word = ''.join(values[:-300])
            coefs = np.asarray(values[-300:], dtype='float32')
            embeddings_index[word] = coefs

    return embeddings_index

# EMBEDDING_PATH = '../embedding_weights/glove.840B.300d.txt'
EMBEDDING_PATH = 'glove.840B.300d.txt'
embeddings = load_glove(EMBEDDING_PATH)

np.save('glove_embeddings.npy', embeddings) 

Ссылка Gist: https://gist.github.com/BrambleXu/634a844cdd3cd04bb2e3ba3c83aef227

Ответ 18

Укажите: # encoding = utf-8 в верхней части вашего файла Python, это должно решить проблему

Ответ 19

Получил ту же ошибку, и это решило мою ошибку. Спасибо! Python 2 и Python 3, отличающиеся обработкой Unicode, делают маринованные файлы совершенно несовместимыми для загрузки. Так что используйте аргумент кодировки Python Pickle. Ссылка ниже помогла мне решить аналогичную проблему, когда я пытался открыть маринованные данные из моего Python 3.7, в то время как мой файл был изначально сохранен в версии Python 2.x. https://blog.modest-destiny.com/posts/python-2-and-3-compatible-pickle-save-and-load/ Я копирую функцию load_pickle в своем скрипте и вызываю load_pickle (pickle_file) во время загрузки моего input_data, как это:

input_data = load_pickle("my_dataset.pkl")

Функция load_pickle находится здесь:

def load_pickle(pickle_file):
    try:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f)
    except UnicodeDecodeError as e:
        with open(pickle_file, 'rb') as f:
            pickle_data = pickle.load(f, encoding='latin1')
    except Exception as e:
        print('Unable to load data ', pickle_file, ':', e)
        raise
    return pickle_data