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

时间:2012-03-10 05:10:46

标签: python unicode python-2.x python-unicode

我真的很困惑。我试图编码,但错误说can't decode...

>>> "你好".encode("utf8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

我知道如何避免字符串上带有“u”前缀的错误。我只是想知道为什么在调用编码时错误是“无法解码”。什么是Python在幕后做什么?

7 个答案:

答案 0 :(得分:156)

"你好".encode('utf-8')

encode将unicode对象转换为string对象。但是你在string对象上调用它(因为你没有你)。所以python必须首先将string转换为unicode对象。所以它相当于

"你好".decode().encode('utf-8')

但解码失败,因为字符串无效ascii。这就是为什么你得到一个关于无法解码的投诉。

答案 1 :(得分:51)

始终编码从unicode到bytes 在这个方向,你可以选择编码

>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print _
你好

另一种方法是从字节解码到unicode 在这方面,你必须知道编码是什么

>>> bytes = '\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print bytes
你好
>>> bytes.decode('utf-8')
u'\u4f60\u597d'
>>> print _
你好

这一点不够强调。如果你想避免玩unicode“whack-a-mole”,重要的是要了解数据层面发生了什么。这里以另一种方式解释:

  • unicode对象已被解码,您永远不想在其上调用decode
  • bytestring对象已经编码,你永远不想在其上调用encode

现在,在看到.encode字节字符串时,Python 2首先尝试将其隐式转换为文本(unicode对象)。类似地,在unicode字符串上看到.decode时,Python 2会隐式尝试将其转换为字节(str对象)。

这些隐式转化是您在致电 Unicode 时获得Decode Error encode的原因。这是因为编码通常接受unicode类型的参数;在接收str参数时,在使用其他编码重新编码之前,会对类型为unicode的对象进行隐式解码。此转换选择默认的'ascii'解码器,为您提供编码器内的解码错误。

事实上,在Python 3中,方法str.decodebytes.encode甚至不存在。他们的撤职是一种[有争议的]企图避免这种常见的混乱。

...或提及的任何编码sys.getdefaultencoding();通常这是'ascii'

答案 2 :(得分:39)

您可以尝试

import sys
reload(sys)
sys.setdefaultencoding("utf-8")

或者

您也可以尝试以下

在.py文件的顶部添加以下行。

# -*- coding: utf-8 -*- 

答案 3 :(得分:8)

如果你正在使用Python&lt; 3,您需要告诉口译员您的string literal is Unicode by prefixing it with a u

Python 2.7.2 (default, Jan 14 2012, 23:14:09) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> "你好".encode("utf8")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>> u"你好".encode("utf8")
'\xe4\xbd\xa0\xe5\xa5\xbd'

进一步阅读Unicode HOWTO

答案 4 :(得分:3)

使用u"你好".encode('utf8')对unicode字符串进行编码。 但是如果你想代表"你好",你应该解码它。就像:

"你好".decode("utf8")

你会得到你想要的。也许你应该更多地了解编码和放大器解码。

答案 5 :(得分:3)

如果您正在处理Unicode,有时而不是encode('utf-8'),您也可以尝试忽略特殊字符,例如

"你好".encode('ascii','ignore')

something.decode('unicode_escape').encode('ascii','ignore') as suggested here

在此示例中不是特别有用,但在无法转换某些特殊字符的其他情况下可以更好地工作。

或者,您可以考虑replacing particular character using replace()

答案 6 :(得分:0)

如果您是从Linux或类似系统(BSD,不确定Mac)上的Shell启动python解释器,则还应检查Shell的默认编码。

从外壳程序(不是python解释器)调用locale charmap,您应该看到

[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

如果不是这种情况,您还会看到其他内容,例如

[user@host dir] $ locale charmap
ANSI_X3.4-1968
[user@host dir] $ 

Python将(至少在某些情况下,例如在我的情况下)继承外壳程序的编码,并且将无法打印(某些?全部?)unicode字符。通过sys.getdefaultencoding()sys.setdefaultencoding()查看和控制的Python自己的默认编码在这种情况下会被忽略。

如果发现此问题,可以通过

进行修复。
[user@host dir] $ export LC_CTYPE="en_EN.UTF-8"
[user@host dir] $ locale charmap
UTF-8
[user@host dir] $ 

(或选择要使用的键盘映射而不是en_EN。)您还可以编辑/etc/locale.conf(或控制系统中语言环境定义的任何文件)来纠正此错误。