编码和解码有什么区别?

186

我一直不确定自己是否理解了str/unicode解码和编码之间的区别。

我知道str().decode()用于当您拥有一系列字节的字符串,并且已知某个字符编码时,给定该编码名称将返回Unicode字符串。

我知道unicode().encode()会根据给定的编码名称将Unicode字符转换为字节字符串。

但是我不理解str().encode()unicode().decode()的作用。有人能解释一下,并可能还纠正我以上任何错误吗?

编辑:

几个答案提供了关于字符串.encode的信息,但没有人似乎知道unicode的.decode是做什么用的。


我认为这个页面的第二个答案已经足够清晰简洁了。 - Ben
7个回答

106

decode 方法用于 Unicode 字符串几乎没有任何应用(除非你有一些非文本数据在 Unicode 字符串中,原因见下文)。我认为它主要是因为历史原因而存在。在 Python 3 中,它已经完全消失了。

unicode().decode() 将使用默认(ascii)编解码器对 s 进行隐式编码。可以通过以下方式进行验证:

>>> s = u'ö'
>>> s.decode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

>>> s.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 0:
ordinal not in range(128)

错误信息完全相同。
对于 str().encode(),情况则正好相反——它尝试使用默认编码对 s 进行隐式的解码
>>> s = 'ö'
>>> s.decode('utf-8')
u'\xf6'
>>> s.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)

这样使用str().encode()是多余的。

但是后一种方法还有另一个有用的应用:存在一些与字符集无关的编码方式,因此可以有意义地应用于8位字符串:

>>> s.encode('zip')
'x\x9c;\xbc\r\x00\x02>\x01z'

你说得对:在这两个应用程序中,"编码"这个词的含义不明确是很尴尬的。然而,在Python 3中,有单独的bytestring类型,这个问题就不存在了。


4
.decode()对Unicode字符串进行解码,例如print u'\\u0203'.decode('unicode-escape') - jfs
很好的例子@J.F.Sebastian在Python3中,我猜你会这样做:print u'\\u0203'.encode('utf8').decode('unicode-escape') - AJP
1
@AJP:在Python 3中:codecs.decode(u'\\u0203', 'unicode-escape') - jfs
@hop:是的。为了检测无效输入并实现Python 2/3兼容性,可以使用ascii编码显式地对字符串进行编码:\\u0203\u00e4'.encode('ascii').decode('unicode-escape') - jfs
@hop:你已经在第一条评论中说了(为什么删除它?不要删除已有回复的评论)我的回复(.encode('ascii').decode('unicode-escape'))并不依赖于sys.getdefaultencoding()。 - jfs

71
将Unicode字符串表示为字节串称为编码。使用u'...'.encode(encoding)
例子:
    >>> u'æøå'.encode('utf8')
    '\xc3\x83\xc2\xa6\xc3\x83\xc2\xb8\xc3\x83\xc2\xa5'
    >>> u'æøå'.encode('latin1')
    '\xc3\xa6\xc3\xb8\xc3\xa5'
    >>> u'æøå'.encode('ascii')
    UnicodeEncodeError: 'ascii'编解码器无法对位置0-5的字符进行编码:序数不在范围内(128)
通常情况下,您需要将Unicode字符串编码成字节串,例如在IO操作中使用它,例如将其传输到网络上或将其保存到磁盘文件中。
将字节串转换为Unicode字符串称为解码。使用unicode('...', encoding)或'...'.decode(encoding)。
例子:
   >>> u'æøå'
   u'\xc3\xa6\xc3\xb8\xc3\xa5' # 解释器以这种方式打印Unicode对象
   >>> unicode('\xc3\xa6\xc3\xb8\xc3\xa5', 'latin1')
   u'\xc3\xa6\xc3\xb8\xc3\xa5'
   >>> '\xc3\xa6\xc3\xb8\xc3\xa5'.decode('latin1')
   u'\xc3\xa6\xc3\xb8\xc3\xa5'
通常情况下,您需要解码字节串,例如从网络或磁盘文件接收字符串数据。
我相信在Python 3中有一些Unicode处理方面的变化,因此上述内容可能不适用于Python 3。
一些好的链接:

6
你没有回答提问者的问题。提问者想知道str.encode()和unicode.decode()是做什么用的。你只是重复了原始问题中所陈述的内容。 - stuckintheshuck
在实践中,你为什么要处理解码和编码的问题,这是一个很好的答案。并不是每台计算机都能理解相同的字符集,但它们都能理解字节。将其编码为计算机通用的字节(可以传输或保存到磁盘),以便计算机能够理解,但在人类需要读取这些字节时(例如在客户端),则需要进行解码。 - Alex Petralia
太棒了!这个回答应该得到赞扬! - sandyp

16

encode方法会将Unicode对象编码成字符串对象,并可在Unicode对象上调用。

decode方法会将以给定编码方式编码的字符串对象解码成Unicode对象,并可在字符串对象上调用。


更详细的解释:

你可以创建一个未设置任何编码方式的Unicode对象,Python会将其存储在内存中,这与你无关。你可以对它进行搜索、拆分及任何你想要的字符串操作。

但是,当你需要将Unicode对象打印到控制台或文本文件中时,就必须对其进行编码(例如使用UTF-8),此时你需要调用encode('utf-8')方法,得到包含'\u<someNumber>'的字符串,这个字符串可以完美地被打印出来。

然后,你可能又需要做相反的操作:读取以UTF-8编码的字符串并将其视为Unicode对象,这样\u360就可以被视为一个字符而不是5个字符。此时,你需要解码该字符串(使用指定的编码方式),得到全新的Unicode对象。

值得一提的是,你也可以选择一些奇怪的编码方式,例如'zip'、'base64'、'rot'等等,它们会将字符串转换为字符串,但我相信最常见的情况是涉及UTF-8/UTF-16和字符串。


12

对于这些编码,mybytestring.encode(somecodec) 是具有意义的:

  • base64
  • bz2
  • zlib
  • hex
  • quopri
  • rot13
  • string_escape
  • uu

我不确定将已经解码的 Unicode 文本再次解码有什么用。尝试使用任何编码进行解码似乎总是会首先尝试使用系统的默认编码进行编码。


5

有一些编码可以用于从str到str或从unicode到unicode的解/编码。例如base64、hex甚至rot13。它们列在codecs模块中。

编辑:

对unicode字符串进行解码操作可以撤销相应的编码操作:

In [1]: u'0a'.decode('hex')
Out[1]: '\n'

返回类型是str而不是unicode,这在我看来是不幸的。但是当你没有将str和unicode进行正确的编解码时,这看起来就像一团糟。


1
-1:解码方法未被应用于Unicode对象。相反,在解码操作开始之前,Unicode对象被编码为“ascii”字节串。为了证明这一点,请尝试执行u'ã'.decode('hex') - 这会导致UnicodeEncodeError错误。 - nosklo
2
@nosklo:您是正确的。我真正想说的是unicode对象有一个decode()方法,因此您也可以将非字符编码编解码器应用于它们。整个非字符编码业务使得Python < 3中的这个接口变得混乱不堪。 - unbeknown

1
简单地说,它们是彼此的完全相反。
计算机使用最基本的字节单位来存储和处理信息;对人类来说是没有意义的。
例如,'\xe4\xb8\xad\xe6\x96\x87' 是两个中文字符的表示,但计算机只有在给定一个字典来查找这个中文词时(在这种情况下,它是一个“utf-8”字典),才知道(意味着打印或存储)它是中文字符,并且如果您查看不同或错误的字典(使用不同的解码方法),它将无法正确显示预期的中文词。
在上述情况下,计算机查找中文词的过程是decode()
计算机将中文写入计算机内存的过程是encode()
因此,编码信息是原始字节,解码信息是原始字节和引用字典的名称(但不是字典本身)。

0

两者互为相反。

  1. 编码是指发送方以特定格式创建消息,使接收方能够读取。

例如:

import base64
def read_csv_file():
 with open( r'File_Path.csv', 'r') as fb:
   csv_read = csv.DictReader(fb)
   for row in csv_read:
     id = row["EMP_ID"].encode("ascii")
     x = base64.b64encode(bytes(id))      #encode
     print(x)
read_csv_file()
  1. 解码是指接收者对编码信息的解释。

    例如:

    print(base64.b64decode(b'SFExMTE='))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接