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


119

我真的很困惑 我尝试编码,但错误提示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到底是做什么的?

Answers:


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

encode将unicode对象转换为string对象。但是这里您已经在string对象上调用了它(因为您没有u)。因此python必须先将转换stringunicode对象。所以它相当于

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

但是解码失败,因为字符串无效的ascii。这就是为什么您会抱怨无法解码的原因。


50
那么解决方案是什么?特别是如果我没有字符串文字,那么我只有一个字符串对象。
乔恩·蒂森

2
@JonTirsen,您不应编码字符串对象。字符串对象已被编码。如果需要更改编码,则需要将其解码为unicode字符串,然后将其编码为所需的编码。
Winston Ewert

20
因此,要清楚地从上面可以说出它"你好".decode('utf-8').encode('utf-8')
deinonychusaur

5
@WinstonEwert我想我很困惑。编码业务往往使我永远困惑。我想我的困惑来自我自己的问题,即我不知道输入是字符串还是unicode字符串以及它可能具有的编码。
deinonychusaur

@deinonychusaur,是的...我明白了。
Winston Ewert

53

始终从unicode 编码为字节。
在这个方向上,您可以选择encoding

>>> 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的“打hack鼠”游戏,那么了解数据级别的情况很重要。这里说明了另一种方式:

  • 一个unicode对象已经被解码了,您再也不想调用decode它了。
  • 一个字节串对象已经被编码,您永远不想调用encode它。

现在,在看到.encode字节字符串时,Python 2首先尝试将其隐式转换为文本(unicode对象)。同样,在看到.decodeunicode字符串时,Python 2隐式尝试将其转换为字节(str对象)。

这些隐式转换是您致电时可以得到的原因。这是因为编码通常接受type的参数;接收参数时,在使用另一种编码对它进行重新编码之前,会对类型进行隐式解码。此转换选择默认的“ ascii”解码器,给您编码器内部的解码错误。UnicodeDecodeErrorencodeunicodestrunicode

事实上,在Python 3的方法str.decodebytes.encode甚至不存在。为了避免这种常见的混淆,将它们移除是一个有争议的尝试。

...或任何编码sys.getdefaultencoding()提及的内容;通常这是“ ascii”


那么,您是说Python在编码之前先解码字节串吗?
thoslin 2012年

正是@thoslin,我添加了更多细节。
2014年

_是什么?为什么打印语句缺少括号?
NoBugs

1
@NoBugs 1.在REPL中,_引用先前的值2.因为这是一个python-2.x问题。
wim

40

你可以试试这个

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

要么

您也可以尝试关注

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

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

8

如果您使用的是Python <3,则需要在解释器前面加上一个前缀,u以告知您的字符串文字是Unicode

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
如果要编码字符串,为什么它会引发解码错误?
MxLDevs 2012年

3

您用于u"你好".encode('utf8')编码unicode字符串。但是,如果要表示"你好",则应该对其进行解码。就像:

"你好".decode("utf8")

您将得到想要的东西。也许您应该了解有关编码和解码的更多信息。



1

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

locale charmap从shell 调用(不是python解释器),您应该看到

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

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

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

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

如果发现此问题,可以通过以下方法解决

[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(或控制系统中区域设置的文件)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.