Python UnicodeDecodeError - 我误解了编码吗?

Posted

技术标签:

【中文标题】Python UnicodeDecodeError - 我误解了编码吗?【英文标题】:Python UnicodeDecodeError - Am I misunderstanding encode? 【发布时间】:2010-09-26 23:55:13 【问题描述】:

关于为什么这不起作用的任何想法?我真的认为“忽略”会做正确的事情。

>>> 'add \x93Monitoring\x93 to list '.encode('latin-1','ignore')
Traceback (most recent call last):
  File "<interactive input>", line 1, in ?
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 4: ordinal not in range(128)

【问题讨论】:

我也写了一篇关于这个主题的长博客:The Hassle of Unicode and Getting on With It 【参考方案1】:

神奇的线是:

unicodedata.normalize('NFKD', text).encode('utf-8', 'ignore')

在最需要的时候不会引发异常的一个衬垫(删除坏的 Unicode 字符...)

【讨论】:

【参考方案2】:

……它们被称为“编码”是有原因的……

前言:将 unicode 视为规范或理想状态。 Unicode 只是一个字符表。 №65 是拉丁文大写 A。№937 是希腊大写 omega。就是这样。

为了让计算机存储和/或操作 Unicode,它必须将其 编码 为字节。 Unicode 最直接的编码是UCS-4;每个字符占用 4 个字节,所有 ~1000000 个字符都可用。这 4 个字节包含 Unicode 表中字符的编号,作为 4 字节整数。另一种非常有用的编码是 UTF-8,它可以将任何 Unicode 字符编码为一到四个字节。但也有一些有限的编码,如“latin1”,其中包含非常有限的字符范围,主要由西方国家使用。这样的编码每个字符只使用一个字节。

基本上,Unicode 可以encoded 有多种编码,编码后的字符串可以解码 为 Unicode。问题是,Unicode 来得太晚了,所以我们这些使用 8 位 字符集 长大的人都太晚了,因为我们一直在使用 编码 字符串。编码可以是 ISO8859-1,或 windows CP437,或 CP850,或,或,或,取决于我们的系统默认值。

因此,当您在源代码中输入字符串“add “Monitoring” to list”(我认为您想要字符串“add “Monitoring” to list”时,请注意第二个引号),您实际上是在使用已根据您系统的默认代码页编码的字符串(我假设您使用的是 Windows 代码页 1252,“Western”)。如果您想从中获取 Unicode,您需要从“cp1252”编码中解码字符串。

所以,你的意思是:

"add \x93Monitoring\x94 to list".decode("cp1252", "ignore")

不幸的是,Python 2.x 也包含一个用于字符串的.encode 方法;这是“特殊”编码的便利功能,例如“zip”或“rot13”或“base64”编码,它们与 Unicode 无关。

无论如何,在来回 Unicode 转换中,您只需要记住:

Unicode 字符串被编码为 Python 2.x 字符串(实际上是字节序列) Python 2.x 字符串解码为 Unicode 字符串

在这两种情况下,您都需要指定将使用的编码

我不是很清楚,我困了,但我当然希望能帮上忙。

PS 一个幽默的旁注:玛雅人没有 Unicode;古罗马人、古希腊人、古埃及人也没有。他们都有自己的“编码”,几乎不尊重其他文化。所有这些文明都化为灰烬。想想吧人!为了人类的利益,让您的应用程序支持 Unicode。 :)

PS2 请不要说“但是中国人……”来破坏前面的信息。但是,如果您倾向于或有义务这样做,请考虑到 Unicode BMP 主要由中文表意文字填充,因此延迟它,因此中文是 Unicode 的基础。只要人们开发支持 Unicode 的应用程序,我就可以继续编造令人发指的谎言。干杯!

【讨论】:

Unicode 不仅仅是一个字符表,例如,单个抽象字符可以由一系列代码点表示:拉丁大写字母 g,带有锐角(对应的编码字符 u"\u01F4" 或 '& #500;') 由序列 u"\u0047\u0301"(或 'Ǵ')表示。 is.gd/eTLi- @J.F. Sebastian:不,Unicode 不仅仅是一个字符表。我只是为了这个答案的目的而过度简化了事情。 另外,我相信 UTF-8 使用 1 到 6 个字节。可能有 2^32 个字符,但编码本身在跟踪多字节序列长度方面有一些开销。 @tchrist:我看不出你写的和我写的有什么不同。想指出你认为我“反过来”描述事物的确切位置吗? @tchrist:在 2008 年,Python 3 比现在少得多,但我仍然注意到我的答案是关于 Python 2,尽管原始报告中报告的异常暗示了这一点问题。【参考方案3】:

这似乎有效:

'add \x93Monitoring\x93 to list '.decode('latin-1').encode('latin-1')

这有什么问题吗?我想知道“忽略”、“替换”和其他此类编码错误处理何时出现?

【讨论】:

当你想编码一个包含在你选择的编码中无法表示的代码点的 unicode 字符串时,它就会出现,即 latin1 中的中文字符。然后,您可以指定编码应如何对此类代码点做出反应。 如上所说,这无济于事。您正在通过一个函数,然后反过来。在最好的情况下,最终的字符串与原始字符串完全相同;在最坏的情况下,您会遇到 Heiko 概述的问题。 似乎有效?? str_object.decode('latin1').encode('latin1') == str_object 适用于所有 STR 对象。换句话说,它什么都不做。 它对 Latin-1 没有任何作用。对于任意字节序列并不总是有效的编码,或者具有相同字符的多个编码的编码,它是不同的。 如果您必须手动操作encode 和/或decode,那么您做错了。【参考方案4】:

encode 可用于 unicode 字符串,但您那里的字符串似乎不是 unicode(尝试使用 u'add \x93Monitoring\x93 to list ')

>>> u'add \x93Monitoring\x93 to list '.encode('latin-1','ignore')
'add \x93Monitoring\x93 to list '

【讨论】:

好吧,字符串是以非 unicode 的方式出现的。所以我需要对字符串做点什么。 这意味着你得到的字符串已经被编码了。在下面的示例中,您只需再次解码和编码 - 假设是 latin-1 编码(这可能并不总是正确的)。我认为您可以简单地继续使用您的字符串,并让输出正确处理它。

以上是关于Python UnicodeDecodeError - 我误解了编码吗?的主要内容,如果未能解决你的问题,请参考以下文章

Python的pymssql库中的UnicodeDecodeError

python2 当中 遇到 UnicodeDecodeError UnicodeDecodeError: 'ascii' codec can't decode byte 0xe

Python UnicodeDecodeError

切换到 Python 3 导致 UnicodeDecodeError

解决问题解决python安装模块时UnicodeDecodeError

Python读取内容UnicodeDecodeError错误