Python - 'ascii'编解码器无法解码字节

41
我正在使用Python 2.6和Jinja2来创建HTML报告。我向模板提供了许多结果,模板通过循环遍历它们并创建HTML表格。
在调用template.render时,我突然收到了这个错误。
<td>{{result.result_str}}</td>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in range(128)

奇怪的是,即使我将result.result_str设置为一个简单的ASCII字符串,比如"abc",我仍然看到这个错误。我对Jinja2和Python都很陌生,希望能得到任何关于如何调查问题并找到根本原因的想法。

7个回答

78
尝试添加这个:
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

它解决了我的问题,祝好运。


这是该帖子中最好的答案,可以节省很多麻烦。 - AlexLordThorsen
reload() 的奥秘是什么?这是魔法吗?(注意:它确实起作用,但我不理解) - Jocelyn delalande
我其实不太明白为什么这个有效,但它确实有效。谢谢。 - bgusach
28
这实际上是糟糕的建议。发帖者应该确保首先将字节字符串解码为Unicode值。设置默认编码类似于用木棍绑着继续走路治疗断腿,而不是去医院接受骨折治疗。 - Martijn Pieters
我误操作点赞了这个答案,因为它似乎提供了一个快速解决方案。但@MartijnPieters是正确的:你应该修复你的bug。 - Christian Pietsch
3
如果我真的希望所有内容都是UTF-8,为什么会有问题? - David Chouinard

43

http://jinja.pocoo.org/docs/api/#unicode

Jinja2在内部使用Unicode,这意味着您必须将Unicode对象传递给render函数或仅由ASCII字符组成的bytestring。

因此,在设置result.result_str的任何位置,您都需要将其转换为unicode格式,例如:

result.result_str = unicode(my_string_variable, "utf8")
< p >(如果你的字节是UTF8编码的Unicode)< /p > < p >或者< /p >
result.result_str = u"my string"

这个答案对我帮助更大,比被采纳的答案还要好。我同意被采纳的答案中的建议——如果我能花一个月的时间来修复我的 100k SLOC webapp,使其在边界处正确地转换字符串为 Unicode 并且只在内部使用 Unicode,那将是非常棒的!但由于资金问题,我无法遵循这个建议。知道 Jinja2 在内部使用 Unicode 帮助我识别出我遇到编码问题的具体位置,并编写了一个修复生产 bug 的解决方案。谢谢你们! - Geoff Gerrietts
1
有没有可能修补Jinja2,使其尝试从utf-8而不是ascii解码?https://dev59.com/KYjca4cB1Zd3GeqPrRSw - anatoly techtonik

20

如果您遇到类似“ABC”的字符串错误,也许非ASCII字符在其他地方。也许在模板源代码中?

无论如何,在整个应用程序中使用Unicode字符串以避免此类问题。如果数据源提供字节字符串,则可以使用byte_string.decode('utf-8')获取Unicode字符串,如果该字符串编码为UTF-8。如果您的来源是文件,请使用codecs模块中的StreamReader类。

如果您不确定Unicode字符串和普通字符串之间的区别,请阅读这篇文章:http://www.joelonsoftware.com/articles/Unicode.html


我检查了非 ASCII 的模板,在 Vim 中运行了 "set isprint=",但它没有显示任何非 ASCII 的内容。 - shane
还有没有其他变量,模板在你发布的那行之后尝试渲染的,可能包含编码字符串的内容?如果没有,你能否将模板简化到最少,以重现错误? - jd.
好主意。我将尝试只显示 result_str 并且不显示其他内容,以查看是否仍然能够得到它。 - shane

11

刚在一段代码中遇到了同样的问题,该代码将Jinja2的输出保存为HTML文件:

with open(path, 'wb') as fh:
    fh.write(template.render(...))

虽然实际问题在于 Python 的 open() 不支持 UTF-8,但很容易归咎于 Jinja2。解决方法很简单:

使用 codecs.open()。

import codecs
with codecs.open(path, 'wb', 'utf-8') as fh:
    fh.write(template.render(...))

5

简单的字符串可能包含UTF-8字符字节,但它们不属于Unicode类型。可以通过"decode"将str转换为unicode来解决此问题。适用于Python 2.5.5。

my_string_variable.decode("utf8")


0

ASCII是一个7位编码。值0xC4无法存储在7位中。因此,您正在使用错误的编码来处理该数据。


1
我明白这个错误的意思。我正在寻找一些指针,以找出为什么会出现这个错误。 - shane
@shane:因为你使用了0xC4。找到这个字符,然后把它删除。 - S.Lott
2
@shane:值得注意的是,0xc4是UTF8编码字符U+0100至U+013F之间的第一个字节(http://www.utf8-chartable.de/unicode-utf8-table.pl?start=256&unicodeinhtml=hex)。 - Martin Stone

-1

或者你可以这样做

export LANG='en_US.UTF-8'

在你运行脚本的控制台中。


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