ChatGPT解决这个技术问题 Extra ChatGPT

Python - “ascii”编解码器无法解码字节

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


W
Winston Ewert
"你好".encode('utf-8')

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

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

但解码失败,因为字符串不是有效的 ascii。这就是为什么您会收到有关无法解码的投诉。


那么解决方案是什么?特别是如果我没有字符串文字,我只有一个字符串对象。
@JonTirsen,您不应该对字符串对象进行编码。字符串对象已被编码。如果需要更改编码,则需要将其解码为 unicode 字符串,然后将其编码为所需的编码。
因此,要从上面清楚地说明,您可以"你好".decode('utf-8').encode('utf-8')
@WinstonEwert 我想我很困惑。编码业务往往让我永远感到困惑。我想我的困惑来自我自己的问题,即不知道输入是字符串还是 unicode 字符串以及它可能具有什么编码。
@deinonychusaur,是的……我明白了。
w
wim

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

>>> 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。

一个字节串对象已经被编码,你永远不想在它上面调用 encode。

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

这些隐式转换是您在调用 encode 时可以获得 UnicodeDecodeError 的原因。这是因为 encoding 通常接受类型为 unicode 的参数;接收 str 参数时,会隐式解码为 unicode 类型的对象,然后再用另一种编码对其进行重新编码。此转换选择默认的“ascii”解码器,从而为您提供编码器内的解码错误。

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

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


那么你的意思是Python在编码之前解码字节串吗?
@thoslin 确切地说,我添加了更多细节。
什么是_,为什么您的打印语句缺少括号?
@NoBugs 1. 在 REPL 中,_ 指的是之前的值 2。因为这是一个 python-2.x 问题。
感谢您的提示。对于我来说,正确的解决方案就是 .decode('utf-8')。我运行了 Subprocess.popen(...).communicate() ,它返回的字节包含德语字符 ä、ö、ü 和正常的 .decode()(没有 'utf-8' 参数)失败。使用 'utf-8' 参数它可以工作。
D
Dadaso Zanzane

你可以试试这个

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

或者

您也可以尝试关注

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

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

这必须被接受的答案!
j
johnsyweb

如果你使用 Python < 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


如果您正在对字符串进行编码,为什么会引发解码错误?
@MxLDevs,因为您无法在编码操作中收到解码错误。
a
aschmid00

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

"你好".decode("utf8")

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


k
kenorb

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

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

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

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

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


0
0range

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

从 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 将(至少在某些情况下,例如在我的情况下)继承 shell 的编码,并且无法打印(一些?全部?) 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(或管理系统中的区域设置定义的任何文件)来更正此问题。