UnicodeEncodeError: 'ascii'编解码器无法将字符u'\xef'编码在位置0处:超出了范围128。

76
我想解析我的XML文档。因此,我已将我的XML文档存储如下:
class XMLdocs(db.Expando):  
   id = db.IntegerProperty()    
   name=db.StringProperty()  
   content=db.BlobProperty()  

现在以下是我的代码:
parser = make_parser()     
curHandler = BasketBallHandler()  
parser.setContentHandler(curHandler)  
for q in XMLdocs.all():  
        parser.parse(StringIO.StringIO(q.content))

我遇到了以下错误:
'ascii' codec can't encode character u'\xef' in position 0: ordinal not in range(128)
Traceback (most recent call last):  
  File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/webapp/__init__.py", line 517, in __call__
    handler.post(*groups)   
  File "/base/data/home/apps/parsepython/1.348669006354245654/mapreduce/base_handler.py", line 59, in post
    self.handle()   
  File "/base/data/home/apps/parsepython/1.348669006354245654/mapreduce/handlers.py", line 168, in handle
    scan_aborted = not self.process_entity(entity, ctx)   
  File "/base/data/home/apps/parsepython/1.348669006354245654/mapreduce/handlers.py", line 233, in process_entity
    handler(entity)   
  File "/base/data/home/apps/parsepython/1.348669006354245654/parseXML.py", line 71, in process
    parser.parse(StringIO.StringIO(q.content))   
  File "/base/python_runtime/python_dist/lib/python2.5/xml/sax/expatreader.py", line 107, in parse
    xmlreader.IncrementalParser.parse(self, source)   
  File "/base/python_runtime/python_dist/lib/python2.5/xml/sax/xmlreader.py", line 123, in parse
    self.feed(buffer)  
  File "/base/python_runtime/python_dist/lib/python2.5/xml/sax/expatreader.py", line 207, in feed
    self._parser.Parse(data, isFinal)   
  File "/base/data/home/apps/parsepython/1.348669006354245654/parseXML.py", line 136, in characters   
    print ch   
UnicodeEncodeError: 'ascii' codec can't encode character u'\xef' in position 0: ordinal not in range(128)   

2
你的堆栈跟踪显示你正在执行的代码与你粘贴的不同 - 而且你正在使用 print。在 WSGI 应用程序中不要使用 print! - Nick Johnson
7个回答

112

这个问题的实际最佳答案取决于您的环境,具体地说,取决于您的终端期望的编码方式。

最快的一行解决方案是将您要打印的所有内容编码为 ASCII,因为您的终端几乎肯定会接受该编码方式,同时舍弃无法打印的字符:

print ch #fails
print ch.encode('ascii', 'ignore')

更好的解决方案是将终端编码更改为UTF-8,并在打印之前将所有内容编码为UTF-8。每次打印或读取字符串时,您应该养成考虑Unicode编码的习惯。


1
在我的情况下,我将 Twitter 流打印到终端,并且一切正常。然后我想将程序的输出重定向到文件,但是我开始收到“ascii”编解码器无法对位置 32-36 的字符进行编码的错误。后来,就像这个答案中所说的那样,我使用了 print tweet.encode("utf-8",ignore) ,然后一切都正常了。 - kommradHomer

56

在Python的最新版本中,只需要在对象末尾加上.encode('utf-8')就可以完成任务。


3
“recent versions of Python” 指的是哪些版本?只包括 3.x,还是也包括 2.7? - kramer65
1
Python 2.7 显然是最近的版本,因为它仍然被广泛使用。 - tmthyjames
1
在我的Python 2.7上运行正常。 - A Star

30

看起来你遇到了 UTF-8 字节序标记(BOM)的问题。试试使用排除 BOM 的 Unicode 字符串:

import codecs

content = unicode(q.content.strip(codecs.BOM_UTF8), 'utf-8')
parser.parse(StringIO.StringIO(content))

我使用了strip而不是lstrip,因为在你的情况下,可能由于连接的文件内容具有多个BOM出现。


我已经按照答案中所述的完全操作,但仍然出现上述错误。起初它在问题中提到的位置0处出错,现在它在先前评论中提到的位置5785处出错。 - mahesh
我建议将任何产生错误的字符串s转换为s = unicode(s.strip(codecs.BOM_UTF8), 'utf-8')。这里的s指的是你的字符串名称。 - Tugrul Ates
尝试将 lstrip 替换为 strip - Tugrul Ates
我理解你的建议,我也曾经详细地犯过同样的错误:ascii' codec can't encode character u'\xef' in position 5785: ordinal not in range(128)。 - mahesh
1
在打印过程中,将Unicode转换为字符串时出现了编码错误。它不会包含UTF-8 BOM,无法解码回Unicode,并且错误是因为它包含非ASCII字符 - 删除它们将破坏内容,而BOM只是其中之一。 - Rosh Oxymoron

30

这个对我有用:

from django.utils.encoding import smart_str
content = smart_str(content)

8
根据您的回溯信息,问题出在 parseXML.py 文件的第 136 行的 print 语句。不幸的是,您没有贴出代码的那一部分,但我猜测它只是用于调试而已。如果您将其改为:
print repr(ch)

如果您想要打印内容,那么至少应该看到您要打印的内容。

2
对于明显的Unicode编码问题,使用非Unicode解决方案是不可取的。 - Kenan Banks
7
Unicode编码问题出现在打印语句中。是的,可能还有其他问题,但解决打印不崩溃的问题是最紧迫的问题。 - Duncan

7

问题在于您试图将Unicode字符打印到可能不支持Unicode的终端上。在打印之前,您需要使用“replace”选项进行编码,例如:print ch.encode(sys.stdout.encoding, 'replace')


打印不是必要的,对我来说出现错误的主要语句是解析语句。 - mahesh
3
@Mahesh:问题是由你的代码造成的,位于parseXML.py的第136行——要么自己修复它,要么把那部分代码展示给我们以便我们帮助你解决。 - John Machin

-1

解决这个问题的简单方法是将默认编码设置为utf8。以下是一个示例:

import sys

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

不要这样做。为什么它会破坏代码 - Mark Tolonen
你能解释一下原因吗? - Hafiz Muhammad Shafiq
我的评论中有一个链接解释了这个问题。基本上,库期望ascii保持默认设置。这就是为什么setdefaultencoding通常不可用,除非使用reload技巧。 - Mark Tolonen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接