关于python:如何修复:“UnicodeDecodeError:’ascii’编解码器无法解码字节”

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
2
3
4
5
6
as3:/usr/local/lib/python2.7/site-packages# cat sitecustomize.py
# encoding=utf8  
import sys  

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

让我检查一下:

1
2
3
4
5
6
7
8
9
10
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。那么错误就不复存在了。


型不要使用流行的答案(sys.setdefaultencoding('utf8'))

这是一个令人讨厌的黑客行为(你必须使用reload),它只会掩盖问题并阻碍你迁移到python 3.x。了解问题,解决根本原因并享受unicode zen。明白为什么不在py脚本中使用sys.setdefaultencoding("utf-8")吗?更多详细信息好的。型tl;dr/快速修复

    百万千克1不要随意解码/编码百万千克1百万千克1不要假设字符串是UTF-8编码的百万千克1百万千克1尝试在代码中尽快将字符串转换为Unicode字符串百万千克1百万千克1修复您的区域设置:如何解决python 3.6中的unicodedecode错误?百万千克1

型python 2.x中的unicode zen-长版本

如果没有找到源头,就很难知道根本原因,所以我得通盘谈谈。好的。型

当您试图将包含非ASCII的python 2.x str转换为Unicode字符串而不指定原始字符串的编码时,通常会发生UnicodeDecodeError: 'ascii' codec can't decode byte。好的。型

简而言之,Unicode字符串是一种完全独立的Python字符串类型,不包含任何编码。它们只保存Unicode点代码,因此可以在整个频谱中保存任何Unicode点。字符串包含编码文本、beit utf-8、utf-16、iso-8895-1、gbk、big5等。字符串解码为Unicode,单码编码为字符串。文件和文本数据总是以编码字符串的形式传输。好的。型

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

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

1
2
3
>>> my_u = u'my ünic?dé str?ng'
>>> type(my_u)
<type 'unicode'>

Unicode字符串也可能来自文件、数据库和网络模块。当发生这种情况时,您不需要担心编码问题。好的。型戈查斯

即使不显式调用unicode(),也可能发生从str到unicode的转换。好的。型

以下情况导致UnicodeDecodeError例外:好的。型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 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:Diagram of a string being converted to a Python Unicode string。好的。型

在这个图中,用ascii调用decode()(这与在没有给定编码的情况下调用unicode()相同)。由于ASCII不能包含大于0x7F的字节,这将引发UnicodeDecodeError异常:好的。型

氧化镁好的。Unicode三明治

在代码中形成一个Unicode三明治是一个很好的实践,在代码中将所有传入的数据解码为Unicode字符串,使用unicode s,然后在退出时编码到str。这可以避免您在代码中间担心字符串的编码。好的。输入/解码源代码

如果需要将非ASCII烘焙到源代码中,只需在字符串前加一个u就可以创建Unicode字符串。例如。好的。

1
u'Zürich'

要允许python解码源代码,您需要添加一个编码头来匹配文件的实际编码。例如,如果您的文件编码为"utf-8",您将使用:好的。

1
# encoding: utf-8

只有在源代码中有非ASCII码时才需要这样做。好的。文件夹

通常从文件接收非ASCII数据。io模块提供了一个文本包装器,可以使用给定的encoding动态解码文件。您必须对文件使用正确的编码-不容易猜到。例如,对于utf-8文件:好的。

1
2
3
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将适合通过降价。如果来自read()行的UnicodeDecodeError,那么您可能使用了错误的编码值。好的。CSV文件

python 2.7 csv模块不支持非ASCII字符??然而,通过https://pypi.python.org/pypi/backports.csv,帮助就在眼前。好的。

像上面一样使用它,但将打开的文件传递给它:好的。

1
2
3
4
5
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

在连接字符串中添加:好的。

1
2
charset='utf8',
use_unicode=True

例如。好的。

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

波斯特雷斯尔

添加:好的。

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

超文本传输协议

网页可以用几乎任何编码进行编码。Content-type头应包含一个charset字段,以提示编码。然后可以根据此值手动解码内容。或者,python请求返回response.text中的单码。好的。手动

如果必须手动解码字符串,则只需执行my_string.decode(encoding),其中encoding是适当的编码。这里给出了支持python 2.x的编解码器:标准编码。同样,如果您得到了UnicodeDecodeError,那么您可能得到了错误的编码。好的。三明治的肉

像处理普通的str一样处理unicodes。好的。产量标准输出/打印

print通过stdout流写入。python尝试在stdout上配置编码器,以便将unicodes编码为控制台的编码。例如,如果Linux shell的localeen_GB.UTF-8,那么输出将被编码为UTF-8。在Windows上,您只能使用8位代码页。好的。

配置不正确的控制台(如损坏的区域设置)可能导致意外的打印错误。PYTHONIOENCODING环境变量可以强制对stdout进行编码。好的。文件夹

就像输入一样,io.open可以用来透明地将单码转换为编码的字节字符串。好的。数据库

相同的读取配置将允许直接写入单码。好的。Python 3

python 3不再像python 2.x那样支持Unicode,但是常规的str现在是Unicode字符串,而旧的str现在是bytes。好的。

默认的编码现在是UTF-8,因此如果您在不提供编码的情况下.decode()一个字节字符串,python 3使用UTF-8编码。这可能修复了50%的人的Unicode问题。好的。

此外,默认情况下,open()以文本模式运行,因此返回解码后的str(Unicode模式)。编码源于您的区域设置,在un*x系统上往往是utf-8,或者在Windows框上是8位代码页,如Windows-1251。好的。好啊。


这是典型的"Unicode问题"。我认为,解释这一点超出了StackOverflow答案的范围,无法完全解释正在发生的事情。

这里解释得很清楚。

在非常简短的总结中,您已经将一些被解释为字节字符串的内容传递给了一些需要将其解码为Unicode字符的内容,但是默认的编解码器(ASCII)失败了。

我指给你的演讲为避免这种情况提供了建议。使代码成为"Unicode三明治"。在python 2中,使用"从未来导入unicode文本"有帮助。

更新:如何修复代码:

好的-在变量"source"中有一些字节。从你的问题中还不清楚他们是如何进入的-也许你是从一个网络表单中读到的?在任何情况下,它们都不是用ASCII编码的,但python尝试将它们转换为Unicode,前提是它们是这样的。您需要明确地告诉它编码是什么。这意味着您需要知道编码是什么!这并不总是容易的,它完全取决于这个字符串的来源。您可以使用一些常见的编码进行试验,例如utf-8。将编码作为第二个参数告诉unicode():

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


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

1
2
3
import sys
reload(sys)  
sys.setdefaultencoding('Cp1252')


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

此错误的原因:输入字符串必须是Unicode,但给出了str

1
"TypeError: Decoding Unicode is not supported"

此错误的原因:试图将Unicode输入字符串转换为Unicode

因此,首先检查您的输入字符串是str并在必要时转换为unicode:

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

其次,上面只更改了类型,但没有删除非ASCII字符。如果要删除非ASCII字符:

1
2
3
4
5
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')


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

unicodedecodeerror: 'ascii' codec can't decode byte 0xe2 in position 5454: ordinal not in range(128)

我最后通过指定"编码"来修复它:

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

希望它也能帮助你。


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

因此,我提出了以下方法来保证来自任一输入的单码或字节字符串。简而言之,包括并使用以下lambda:

1
2
3
4
5
6
# 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)

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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))

下面是关于这个的一些更多的理由。


Encode将中的Unicode对象转换为字符串对象。我认为您正在尝试对字符串对象进行编码。首先将结果转换为Unicode对象,然后将该Unicode对象编码为"utf-8"。例如

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

要在Ubuntu安装的操作系统级别上解决此问题,请检查以下内容:

1
$ locale charmap

如果你得到

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

而不是

1
UTF-8

然后将LC_CTYPELC_ALL设置如下:

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


我也有同样的问题,但它不适用于Python3。我按照这个方法解决了我的问题:

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

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


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

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

有关解释,请参见@alastair mccormack's detailed answer。


我对弦乐"粉笔机"也有同样的问题。-一个马洛卡",我解决了:

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

在django(1.9.10)/python 2.7.5项目中,我经常遇到UnicodeDecodeError异常;主要是在我尝试向日志提供unicode字符串时。我为任意对象创建了一个助手函数,基本上将格式设置为8位ASCII字符串,并将表中不包含的任何字符替换为"?"。我认为这不是最好的解决方案,但由于默认编码是ASCII(我不想更改它),它将做到:

1
2
3
4
5
6
7
8
9
10
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))


我也有同样的错误,URL包含非ASCII字符(值大于128的字节)

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

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

在我的例子中,在python 2.7中,我认为这个分配改变了str内部表示中的"某物"——也就是说,它强制正确解码url中的备份字节序列,最后将字符串放入一个utf-8 str,所有的魔力都在正确的位置。Python中的Unicode对我来说是黑色的魔法。希望有用


当我们的字符串中有一些非ASCII字符,并且我们在没有正确解码的情况下对该字符串执行任何操作时,就会发生此错误。这帮助我解决了我的问题。我正在读取一个csv文件,其中包含列id、文本和解码字符,如下所示:

1
2
3
4
5
6
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

而且因为读手套文件需要很长时间,我建议把手套文件变成一个麻木的文件。当netx time读取嵌入权重时,它将节省您的时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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/634a844cd3cd04bb2e3ba3c83aef277


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