如何解决:“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被解码为Unicode , Unicodes被编码为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的转换。
以下情况会导致UnicodeDecodeError
exception:
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是成功的:
在这个图中, decode()
是用ascii
调用的(这与调用unicode()
没有给定的编码相同)。 由于ASCII不能包含大于0x7F
字节,这将引发一个UnicodeDecodeError
exception:
Unicode三明治
在代码中形成一个Unicode三明治是一个很好的做法,在这里你将所有传入的数据解码为Unicodestring,与Unicodes一起工作,然后在出门时编码。 这样可以避免担心代码中间的string编码问题。
input/解码
源代码
如果您需要在源代码中烘焙非ASCII字符,只需在string前加u
即可创buildUnicodestring。 例如
u'Zürich'
为了允许Python解码你的源代码,你需要添加一个编docker来匹配文件的实际编码。 例如,如果您的文件编码为“UTF-8”,则可以使用:
# encoding: utf-8
只有在源代码中使用非ASCII码时才有必要。
档
通常从文件接收非ASCII数据。 io
模块提供了一个TextWrapper,可以使用给定的encoding
dynamic解码文件。 您必须使用正确的编码文件 – 它不能被轻易猜出。 例如,对于一个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的locale
是en_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项目中,我频繁出现UnicodeDecodeError
exception; 主要是当我尝试提供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 -*-