【问题标题】:understanding decode() and encode() unicode [duplicate]理解 decode() 和 encode() unicode [重复]
【发布时间】:2015-03-27 21:41:06
【问题描述】:

我只是无法理解函数 decode() 和 encode() 在 python2.7 上的工作原理

我尝试了以下语句

>>> s = u'abcd'
>>> s.encode('utf8')
'abcd'
>>> s.encode('utf16')
'\xff\xfea\x00b\x00c\x00d\x00'
>>> s.encode('utf32')
'\xff\xfe\x00\x00a\x00\x00\x00b\x00\x00\x00c\x00\x00\x00d\x00\x00\x00'

直到这里,我认为很清楚; encode() 在对应的 utf-8/16/32 字节字符串中翻译一个 unicode 代码。

但是当我编码时:

>>> s.decode('utf8')
u'abcd'
>>> s.decode('utf16')
u'\u6261\u6463'
>>> s.decode('utf32')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/encodings/utf_32.py", line 11, in decode
    return codecs.utf_32_decode(input, errors, True)
UnicodeDecodeError: 'utf32' codec can't decode bytes in position 0-3: codepoint not in range(0x110000)

为什么decode() 在 unicode 类型上的含义?为什么第一个(使用 utf8)工作而不是后者?是不是因为python内部使用utf-8存储unicode字符串?

最后一件事:

>>> s2 = '≈'
>>> s2
'\xe2\x89\x88'

幕后发生了什么? '≈' 不是 ascii 字符,那么 python 是否使用编码 sys.getfilesystemencoding() 返回隐式转换它?

【问题讨论】:

  • Martijn 的回答解释了这种情况。值得注意的是,这种混淆在 Python 3 中被清除了。在 Python 3 中,unicode 对象没有decode 方法,而字节对象没有encode 方法,所以你不能不小心进行编码/解码方向错误。
  • 你能不能不要继续扩大你的问题?

标签: python python-2.7 unicode encoding


【解决方案1】:

您在 unicode 字符串上调用 decode。 Python 首先使用默认的 ASCII 编解码器对字符串进行编码,这样您就可以到解码实际字节。您无法自行解码 Unicode 数据,它已经解码了。

然后解码失败,因为字节不是有效的 UTF-32 数据。字节串'abcd' 可解码为 UTF-8,因为 ASCII 是 UTF-8 的子集。编码为 ASCII 然后解码为 UTF-8 会产生相同的信息。以 UTF-16 解码是偶然的;您提供了 4 个字节,十六进制值为 0x61、0x62、0x63 和 0x64(字符 abcd 的 ASCII 值),这些字节可以解码为 \u6261 和 \u6463 的 UTF-16 little endian。但是在 UTF-32 编码系统中,这 4 个字节没有有效的解码。

如果s 中的数据不能先编码为ASCII,您将得到UnicodeEncodeError 异常;请注意该名称中的 Encode:

>>> u'åßç'.decode('utf8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

因为对字节串的隐式编码失败。

在 Python 3 中,unicode 对象已重命名为 str,并从类型中删除了 str.decode() 方法以防止这种混淆。只剩下str.encode()。 Python str 类型已被 bytes 类型替换,后者只有一个 bytes.decode() 方法。

您的第二个示例显示您在终端或控制台中以交互方式使用 Python 解释器。 Python 从终端接收您的输入作为 UTF-8 字节并将这些字节存储在一个字节串中。如果您使用 unicode 文字,Python 将使用为您的终端声明的编码自动解码这些字节;你可以反省sys.stdin.encoding 看看 Python 检测到了什么:

>>> import sys
>>> sys.stdin.encoding
'UTF-8'
>>> s = '≈'
>>> s
'\xe2\x89\x88'
>>> s = u'≈'
>>> s
u'\u2248'
>>> print s
≈

反之亦然,在打印时,sys.stdout.encoding 编解码器用于将 Unicode 字符串自动编码为终端使用的编解码器,然后再次解释这些字节以在您的屏幕上显示正确的字形。

如果您不是在 Python 交互式解释器中工作,而是在使用 Python 源文件,则要使用的编解码器由 PEP-263 Python source code encodings declaration 确定,因为 Python 2 否则默认将字节解码为 ASCII。

sys.getfilesystemencoding()与这一切无关;它告诉你 Python 认为你的 文件系统元数据 是用什么编码的;例如目录中的文件名。当您将unicode 路径用于与文件系统相关的调用(如os.listdir())时,将使用这些值。

【讨论】:

  • 答案的最后一部分让我很困惑:s = '≈',然后是'\xe2\x89\x88',因为 Python 接收到的字符是 utf-8 字符,而我从 sys.stdin.encoding 看不到它返回utf-8。现在,如果我使用 s = u'≈',我不明白你想说什么
  • @antox:u'≈'.encode('utf8') == '\xe2\x89\x88'。 ≈ 的 UTF-8 编码就是这 3 个字节。
  • 那么您的意思是str 和unicode 类型使用sys.stdin.encoding 返回的编码存储值吗?以同样的方式?
  • @antox:不,str 存储了字节。 unicode 存储 unicode,但您需要先解码字节。 Python 将使用sys.stdin.encoding 来做后者。
  • @antox:但是,您的终端将始终发送字节。
猜你喜欢
  • 2016-03-02
  • 2011-06-28
  • 1970-01-01
  • 2016-02-24
  • 2013-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-16
相关资源
最近更新 更多