如何修复: “ UnicodeDecodeError: ‘ ascii’codec 无法解码字节”

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/,中文帖子可以成功发表。

1221117 次浏览

这是典型的“统一码问题”。我相信,解释这个问题已经超出了StackOverflow回答的范围,无法完全解释正在发生的事情。

这是很好的解释在这里

简单地说,您已经将一个被解释为字节字符串的内容传递给了需要将其解码为Unicode字符的内容,但是默认的编解码器(ascii)失败了。

我给你们看的演示提供了避免这种情况的建议。让你的代码成为“unicode三明治”。在Python 2中,使用from __future__ import unicode_literals会有所帮助。

更新:如何修复代码:

在变量“source”中有一些字节。从你的问题中不清楚它们是如何进入那里的——也许你是从网络表格中读到的?在任何情况下,它们都不是用ascii编码的,但python正在尝试将它们转换为unicode,假设它们是。你需要显式地告诉它编码是什么。这意味着你需要知道编码是什么!这并不总是容易的,这完全取决于这个字符串来自哪里。您可以尝试使用一些常见的编码-例如UTF-8。你告诉unicode()编码作为第二个参数:

source = unicode(source, 'utf-8')

最后我明白了:

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。那么错误就不再存在了。

在某些情况下,当你检查你的默认编码(print sys.getdefaultencoding())时,它返回你正在使用ASCII。如果您更改为UTF-8,它将不起作用,这取决于变量的内容。 我找到了另一种方法:

import sys
reload(sys)
sys.setdefaultencoding('Cp1252')

我发现最好的方法是始终转换为unicode -但这很难实现,因为在实践中,您必须检查并将每个参数转换为您编写的包含某种形式的字符串处理的每个函数和方法。

因此,我提出了以下方法,以保证从任何一个输入中获得unicode或字节字符串。简而言之,包括和使用以下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))

这里有更多关于这个的推理

Tl;dr /快速修复

Unicode Zen in Python 2。x -长版本

没有看到源头就很难知道根本原因,所以我只能笼统地说一下。

UnicodeDecodeError: 'ascii' codec can't decode byte通常发生在你试图转换Python 2时。将包含非ascii的str转换为Unicode字符串,而不指定原始字符串的编码。

简而言之,Unicode字符串是完全独立的Python字符串类型,不包含任何编码。它们只保存Unicode 点代码,因此可以保存整个光谱中的任何Unicode点。字符串包含编码文本,如UTF-8, UTF-16, ISO-8895-1, GBK, Big5等。字符串被解码为Unicodeunicode被编码为字符串。文件和文本数据总是以编码字符串的形式传输。

Markdown模块作者可能使用unicode()(抛出异常的地方)作为其余代码的质量门——它将转换ASCII或将现有的Unicode字符串重新包装为新的Unicode字符串。Markdown作者无法知道传入字符串的编码,因此将依赖于您在传递给Markdown之前将字符串解码为Unicode字符串。

Unicode字符串可以在代码中使用字符串的u前缀来声明。如。

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

Unicode字符串也可以来自文件、数据库和网络模块。当这种情况发生时,您不需要担心编码。

陷阱

即使没有显式调用unicode(),也可能发生从str到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 Unicode: 一个字符串被转换为Python Unicode字符串的图表 < / p >

在这个图中,decode()是通过ascii调用的(这与调用unicode()时没有给出编码是一样的)。由于ASCII不能包含大于0x7F的字节,这将引发UnicodeDecodeError异常:

字符串转换为编码错误的Python Unicode字符串的图表

Unicode三明治

在你的代码中形成一个Unicode三明治是一个很好的实践,在这里你将所有传入的数据解码为Unicode字符串,使用Unicode,然后在输出时编码为strs。这使您不必担心在代码中间对字符串进行编码。

输入/解码

源代码

如果你需要在你的源代码中加入非ascii,只需要在字符串前加上u来创建Unicode字符串。如。

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。如果read()行中有UnicodeDecodeError,那么你可能使用了错误的编码值。

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格式的数据,但通常需要进行一些配置。SQL查询总是使用Unicode字符串。

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中的unicode。

手动

如果必须手动解码字符串,可以简单地执行my_string.decode(encoding),其中encoding是适当的编码。Python 2。x支持的编解码器在这里给出:标准编码。同样,如果你得到UnicodeDecodeError,那么你可能得到了错误的编码。

三明治里的肉

使用unicode就像使用普通字符串一样。

输出

标准输出/打印

print通过标准输出流写入。Python尝试在stdout上配置编码器,以便将unicode编码为控制台的编码。例如,如果Linux shell的localeen_GB.UTF-8,则输出将被编码为UTF-8。在Windows上,你将被限制在一个8位的代码页。

配置错误的控制台(例如已损坏的区域设置)可能导致意外的打印错误。PYTHONIOENCODING环境变量可以强制编码为stdout。

文件

就像输入一样,io.open可用于透明地将unicode转换为编码的字节字符串。

数据库

读取的相同配置将允许直接写入unicode。

Python 3

Python 3并不比Python 2更支持Unicode。X是,但它在这个主题上稍微不那么困惑。例如,常规的str现在是Unicode字符串,旧的str现在是bytes

默认的编码是UTF-8,所以如果你.decode()一个字节字符串而不给出编码,Python 3使用UTF-8编码。这可能解决了50%的人的Unicode问题。

此外,open()默认情况下以文本模式运行,因此返回解码后的str (Unicode)。编码源自您的区域设置,在Un*x系统上通常是UTF-8,在Windows盒子上通常是8位代码页,例如Windows -1251。

为什么你不应该使用sys.setdefaultencoding('utf8')

这是一个讨厌的黑客(你必须使用reload是有原因的),它只会掩盖问题,阻碍你迁移到Python 3.x。理解问题,解决根本原因,享受Unicode禅。 更多细节见为什么我们不应该在py脚本中使用sys.setdefaultencoding("utf-8") ?

在Django (1.9.10)/Python 2.7.5项目中,我经常遇到UnicodeDecodeError异常;主要是当我试图向日志记录提供unicode字符串时。我为任意对象创建了一个辅助函数,基本上格式化为8位ascii字符串,并将表中不包含的任何字符替换为'?'。我认为这不是最好的解决方案,但由于默认编码是ascii(我不想改变它),它会这样做:

< p > < >之前 encode_for_logging(c, encoding='ascii'): 如果isinstance(c, basestring): 返回c.encode(encoding, 'replace') elif isinstance(c, Iterable): C_ = [] 对于v (c) c_。追加(encode_for_logging (v,编码) 返回c_ 其他: 返回encode_for_logging (unicode (c)) < / >之前' < / p >

我得到了字符串“PastelerÃ-a Mallorca”同样的问题,我用:

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

我遇到了同样的问题,但它不适用于Python 3。我遵循了这个方法,解决了我的问题:

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

在读取/写入文件时,必须设置编码。

"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')

Encode将unicode对象转换为字符串对象。我认为你正在尝试编码一个字符串对象。首先将结果转换为unicode对象,然后将该unicode对象编码为'utf-8'。 例如< / p >

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

简而言之,为了确保在Python 2中正确处理unicode:

  • 使用io.open读取/写入文件
  • 使用from __future__ import unicode_literals
  • 配置其他数据输入/输出(例如,数据库,网络)使用unicode
  • 如果不能将输出配置为utf-8,则将输出转换为print(text.encode('ascii', 'replace').decode())

有关解释,请参阅@Alastair McCormack的详细的回答

我正在搜索解决以下错误信息:

Unicodedecodeerror: 'ascii'编解码器无法解码位置5454中的字节0xe2:序号不在范围(128)

我最终通过指定'encoding'来修复它:

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

希望它也能帮助到你。

我有同样的错误,url包含非ascii字符(值> 128的字节),我的解决方案:

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

注意:utf-8, utf8只是别名。只使用'utf8'或'utf-8'应该以同样的方式工作

在我的情况下,为我工作,在Python 2.7中,我假设这个赋值改变了str内部表示中的“某些东西”——即。,它强制对url中支持的字节序列进行正确解码,并最终将字符串放入utf - 8 str中,并在正确的地方使用所有魔法。 Python中的Unicode对我来说是一种黑魔法。 希望有用的< / p >

当字符串中有一些非ASCII字符,并且我们在没有正确解码的情况下对该字符串执行任何操作时,会发生此错误。 这帮我解决了我的问题。 我正在阅读一个列ID,文本和解码字符的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)
这是我的解决方案,只需添加编码。 with open(file, encoding='utf8') as f < / p >

因为读取glove文件需要很长时间,所以我建议将glove文件转换为numpy文件。当你读取嵌入权重时,它将节省你的时间。

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)

要点链接:https://gist.github.com/BrambleXu/634a844cdd3cd04bb2e3ba3c83aef227

在你的Python文件顶部指定:# encoding= utf-8,它应该能解决这个问题

为了在Ubuntu安装的操作系统层面上解决这个问题,请检查以下内容:

$ locale charmap

如果你得到

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

而不是

UTF-8

然后像这样设置LC_CTYPELC_ALL:

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

得到一个相同的错误,这解决了我的错误。谢谢! Python 2和Python 3在unicode处理方面的差异使得pickle文件在加载时非常不兼容。因此使用python pickle的encoding参数。下面的链接帮助我解决了类似的问题,当我试图从python 3.7打开pickle数据时,而我的文件最初保存在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

这招对我很管用:

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

我在Python2.7中遇到了这个错误。我在尝试运行许多python程序时遇到了这种情况,但我设法用这个简单的脚本重现了它:

#!/usr/bin/env python


import subprocess
import sys


result = subprocess.Popen([u'svn', u'info'])
if not callable(getattr(result, "__enter__", None)) and not callable(getattr(result, "__exit__", None)):
print("foo")
print("bar")

在成功的情况下,它应该打印出'foo'和'bar',如果你不在svn文件夹中,可能会有一个错误消息。

失败时,它应该打印'UnicodeDecodeError: 'ascii'编解码器无法解码位置39中的0xc4字节:序号不在范围(128)'

在尝试重新生成区域设置和这个问题中发布的许多其他解决方案后,我了解到发生了错误,因为我的PATH环境变量中编码了一个特殊字符(ĺ)。在修复了“~ / . bashrc”中的PATH后,退出我的会话并再次进入,(显然源“~ / . bashrc”不起作用),问题就消失了。