如何解决:“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/中 ,中文文章可以成功发布。

最后我明白了:

 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 。 那么错误是没有更多。

TL;博士

  • 不要解码/编码威利
  • 不要以为你的string是UTF-8编码的
  • 尝试在您的代码中尽快将string转换为Unicodestring

Python 2.x – 长版本

没有看到源头,很难知道根本原因,所以我必须一般地讲。

UnicodeDecodeError: 'ascii' codec can't decode byte当您尝试将包含非ASCII的Python 2.x str转换为Unicodestring而不指定原始string的编码时, UnicodeDecodeError: 'ascii' codec can't decode byte

简而言之,Unicodestring是一个完全独立的Pythonstring,不包含任何编码。 它们只保存Unicode 点代码 ,因此可以保存整个频谱的任何Unicode点。 string包含编码的文本,比如UTF-8,UTF-16,ISO-8895-1,GBK,Big5等。 string被解码为UnicodeUnicodes被编码为string 。 文件和文本数据总是以编码的string传输。

Markdown模块的作者可能使用unicode() (其中抛出exception)作为其余代码的质量门 – 它将转换ASCII或将现有的Unicodesstring重新包装为新的Unicodestring。 Markdown作者无法知道传入string的编码,所以在传递给Markdown之前,将依赖于将string解码为Unicodestring。

Unicodestring可以在您的代码中使用string的u前缀来声明。 例如

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

Unicodestring也可能来自文件,数据库和networking模块。 发生这种情况时,您不必担心编码。

陷阱

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

以下情况会导致UnicodeDecodeErrorexception:

 unicode('€') # explicit conversion without encoding u"The currency is: {}".format('€') # new style format string into Unicode string - Python will try to convert value string to Unicode first u'The currency is: %s' % '€' # old style format string into Unicode string - Python will try to convert value string to Unicode first u'The currency is: ' + '€' # append string to Unicode - Python will try to convert string to Unicode first 

例子

在下图中,您可以看到词café是如何根据terminaltypes以“UTF-8”或“Cp1252”编码进行编码的。 在这两个例子中, caf只是一般的ascii。 在UTF-8中,使用两个字节进行编码。 在“Cp1252”中,é是0xE9(这也恰好是Unicode点值(这不是巧合))。 正确的decode()被调用,并且转换成Python Unicode是成功的: 被转换为Python Unicode字符串的字符串图

在这个图中, decode()是用ascii调用的(这与调用unicode()没有给定的编码相同)。 由于ASCII不能包含大于0x7F字节,这将引发一个UnicodeDecodeErrorexception:

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

Unicode三明治

在代码中形成一个Unicode三明治是一个很好的做法,在这里你将所有传入的数据解码为Unicodestring,与Unicodes一起工作,然后在出门时编码。 这样可以避免担心代码中间的string编码问题。

input/解码

源代码

如果您需要在源代码中烘焙非ASCII字符,只需在string前加u即可创buildUnicodestring。 例如

 u'Zürich' 

为了允许Python解码你的源代码,你需要添加一个编docker来匹配文件的实际编码。 例如,如果您的文件编码为“UTF-8”,则可以使用:

 # encoding: utf-8 

只有在源代码中使用非ASCII码时才有必要。

通常从文件接收非ASCII数据。 io模块提供了一个TextWrapper,可以使用给定的encodingdynamic解码文件。 您必须使用正确的编码文件 – 它不能被轻易猜出。 例如,对于一个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返回数据,但通常需要一些configuration。 始终使用Unicodestring进行SQL查询。

MySQL的

在连接string中添加:

 charset='utf8', use_unicode=True 

PostgreSQL的

加:

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

HTTP

网页可以用任何编码进行编码。 Content-type头应该包含一个charset字段来提示编码。 内容然后可以手动解码这个值。 或者, Python-Requests在response.text返回Unicodes。

手动

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

三明治的肉

像普通strs一样使用Unicodes。

产量

标准输出/打印

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

configuration不正确的控制台(如损坏的区域设置)可能会导致意外的打印错误。 PYTHONIOENCODING环境variables可以强制stdout的编码。

就像input一样, io.open可以用来将Unicodes透明地转换为编码的字节串。

数据库

读取相同的configuration将允许Unicodes直接写入。

Python 3

Python 3没有更多的Unicode能够像Python 2.x一样,但是常规的str现在是一个Unicodestring,旧的str现在是bytes

缺省编码现在是UTF-8,所以如果你在不给出编码的情况下解码.decode()一个字节string,Python 3使用UTF-8编码。 这大概解决了50%的人的Unicode问题。

此外, open()默认在文本模式下运行,因此返回解码的str (Unicode)。 编码是从您的语言环境派生而来的,这些语言环境通常在Un * x系统上是UTF-8,或者在Windows上是8位代码页,例如windows-1251。

这是经典的“unicode问题”。 我相信解释这是超出了StackOverflow答案的范围,以完全解释发生了什么。

这里很好的解释。

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

我指出你提供的build议是为了避免这个问题。 让你的代码成为“unicode三明治”。 在Python 2中,使用“from __future__ import unicode_literals”有帮助。

更新:如何修复代码:

好的 – 在你的variables“source”中你有一些字节。 从你的问题来看,他们是如何进入的 – 也许你是从networking表单读取的? 在任何情况下,它们都不用ascii编码,但python试图将它们转换为unicode,假设它们是。 你需要明确地告诉它编码是什么。 这意味着你需要知道什么是编码! 这并不总是很容易,而且完全取决于这个string是从哪里来的。 您可以尝试一些常见的编码 – 例如UTF-8。 你把unicode()的编码告诉第二个参数:

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

在某些情况下,当你检查你的默认编码( print sys.getdefaultencoding() )时,它返回你正在使用的ASCII。 如果您更改为UTF-8,则它不起作用,具体取决于variables的内容。 我发现另一种方式:

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

这个错误主要是因为你的上下文需要一个unicodestring,但是传递的只是一个string。 在你转换成代码检查之前,如果string已经在unicode,在这种情况下,你将得到一个TypeError:解码Unicode不支持,因为你试图转换成unicode一个string已经在unicode。在你转换为下面:

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

在上面添加,上面不删除不支持的字符。 它只是改变types,但非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') 

我发现最好的办法是始终转换为unicode – 但这很难实现,因为在实践中,您必须检查每个参数并将其转换为您编写的每个函数和方法,包括某种forms的string处理。

所以我想出了以下方法,以保证unicodes或字节string,从任何input。 总之, 包括并使用以下lambda:

 # 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)) 

这里有一些更多的推理 。

编码将一个unicode对象转换为一个string对象。 我想你正在尝试编码一个string对象。 首先将您的结果转换为unicode对象,然后将该unicode对象编码为“utf-8”。 例如

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

我遇到了同样的问题,string“PasteleràMallorca”,我解决了:

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

我有同样的问题,但它不适用于Python 3.我遵循这一点,它解决了我的问题:

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

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

在Django(1.9.10)/ Python 2.7.5项目中,我频繁出现UnicodeDecodeErrorexception; 主要是当我尝试提供unicodestringlogging。 我为任意对象做了一个辅助函数,基本上格式化为8位asciistring,并将不在表中的任何字符replace为'?'。 我认为这不是最好的解决scheme,但由于默认编码是ascii(我不想改变它),它会做:

 def encode_for_logging(c,encoding ='ascii'):
    如果isinstance(c,basestring):
        返回c.encode(编码,'replace')
     elif isinstance(c,Iterable):
         c_ = []
         for v in c:
             c_.append(encode_for_logging(v,encoding))
        返回c_
    其他:
        返回encode_for_logging(unicode(c))

`

添加python文件的顶部。 这将转换您的代码文件为Unicode这不会修复所有的情况下。 但是这个代码和我很多次相同

 # -*- coding:utf-8 -*- 
Interesting Posts