字符编码

我们眼睛看到的电脑上显示的字,包括汉字、英文、日文、韩文,这些文字,在计算机内部是怎么存储的?

难道是刻上去的? 比如刻在硬盘上一个个这样的字?

当然不是,计算机都是用数字存储信息的。

用 磁场、电信号 等物理介质的 正负 状态 表示 0 和 1, 位数增加上去就可以存储很大的数字了。

根据不同的使用场合,数字可以表示不同的意义。

比如,需要存储 颜色信息的时候, 0 可以用来代表 白色, 1 代表红色, 2 代表 黑色等等。

如果有10000种颜色,可以用 0 到 9999 一共 10000个数字分别代表他们。

同样的, 我们要存储 文字信息,也可以用不同的数字来代表不同的文字。

字符集

计算机是美国人发明的,所以在开始的时候, 他们也没有想到将来要支持全世界的文字。

所以,最早的时候,他们定义了一个规范,定义一些数字 用来代表美国人使用的文字符号。

而美国人的单词都是用字母拼出来的, 所以他们常用的基础文字符号比较少。

就是字母,再加上 !@#$%^&*(){[]}+- 等等这些符号,也就100多个。

他们定义的规范就叫 ASCII (American Standard Code for Information Interchange) ,中文大意就是 美国信息交换标准码

大家可以参考 百度上面的ASCII表

这个 ASCII 码里面用128个数字代表了128个字符。

要存储和传输这 128个字符对应的文字信息 也很简单, 二进制有 8 位就足够了。

因为2的8次方等于256,可以存储 从 0 到255 一共 256个数字, 可以表示 最多 256 个文字符号。

二进制有 8 位 的长度 被称为 一个 字节

所以一个字节就可以存放 任何一个ASCII 文字符号。

ASCII 这样的 用数字代表文字符号的规范,就被称之为 字符集


后来计算机传遍了全世界,其它国家的文字符号就多了。

我们中文,就有这么多的文字符号。小学的时候,我们有个3000常用字表(我骄傲一下,小学1年级我就认识了近2000多个字), 光常用字就有3千个。

当然还有 韩文、日文、繁体中文、阿拉伯文等等。

显然ASCII是不够的,我们需要其它的数字来代表这些文字符号。

开始各个国家和地区 自己定义了自己的 字符集。

比如我们中国就定义另外一套规范, 规定了 用什么样的数字代表什么样的文字符号。

这套规范也在不断的升级,包括 GB2312、GBK、GB18030


各个国家定义了各国的文字的字符集,这就带来了一个问题。

现在全球交流很密切,有时一篇文章会使用多国文字,比如 同时使用 日文和中文。 而没有各国的字符集是不包含别国文字的, 这时就没法在一篇文章中存储多国文字了。

为了解决这个问题。 国际标准化组织定义了一个字符集,想包括世界上所有的文字符号。

这就是大名鼎鼎的 unicode 字符集。

这个字符集里面包括了现今世界上的常用文字符号 和 其对应的数字表示。

这样就解决了在一篇文章中包含多国文字的问题了。


字符编码

unicode 出现了,很好,但是还有一个问题。 字符怎么存储和传输。

最初只有ASCII码的时候,一个字节(最多可以表示256个字符)就可以存储传输任何文字。

所以软件硬件对 每个字符都是用字节(8位二进制数字)来进行存储、传输的。 没有什么问题。

但是unicode里面有10多万的文字符号,数字范围 远远 超过 一个字节所能代表的数字。

所以一个字节不够。

那么怎么用多个字节来 表示这些数字呢?

这就有需要另外的规范。这些 如何用字节表示 字符对应的数字 就是 字符编码 规范

unicode字符 的编码,最常用的规范是 UTF8 和 UTF16

比如 UTF8 表示 中文字符 ,就是用 3个字节表示的,对应的16进制表示是 E4 、BD、 A0


当然我们中文字符集gb系列使用另外的编码规范。

以后,我们会写一篇文章,以UTF8为例,讲解它是如何用多个字节存储 数字的。

这里我们只要知道 不同的 编码规范 对数字有不同的 用字节表示的方法就行了。

有了编码规范,字符集 中的数字就可以进行存储和传输了。


Python3 的字符编码和解码

字符串编码

我们Python3语言里面的字符串对象是unicode字符串,在内存中实际存储时,使用的是 UTF16 编码。

但是我们通常不会将UTF16编码的内容写到磁盘或者在网络进行传输, 因为utf16编码比较浪费空间。

特别是如果文字信息基本都是英文符号的情况下, utf16 都会用2个字节来代表英文符号。 一个字节其实就够了。

所以,Python语言要对字符串对象 进行存储和传输的时候,通常要使用字符串的encode方法,参数指定编码方式,编码为一个 bytes 对象。

bytes对象的底层就是用一个个的字节来存储字符串中的文字的。

同样的字符串,用不同的编码方式,有时会产生不同的bytes结果。

比如

print ('你好'.encode('utf8')) # 输出 b'\xe4\xbd\xa0\xe5\xa5\xbd'
print ('你好'.encode('gbk'))  # 输出 b'\xc4\xe3\xba\xc3'

输出内容 中 b 开头,表示这是一个 字节串bytes 对象

\x 说明是用16进制表示一个字节

你好 两个字,使用 utf8 编码 后的字节串,用16进制来表示 就是6个字节 e4bda0 e5a5bd

e4bda0 对应 你
e5a5bd 对应 好

你好 两个字,使用 gbk 编码 后的字节串,用16进制来表示 却是4个字节 c4e3 bac3

c4e3 对应 你
bac3 对应 好

encode方法返回的是编码后的字节串对象bytes 编码为字节串对象 bytes 就可存储到文件或者传输到网络中去了。 我们后面的学习会讲如何进行文件存储和网络传输

字节串解码

当我们的Python程序从文件中读入文字信息, 从网络上接收 文字信息,获取的数据通常是使用某种字符编码后的 字节串。

程序通常需要解码这些 字节串字符串 ,这样才方便程序 理解和处理 字符信息。

Python语言的解码 都是解码成 unicode字符串对象。

要解码字节串,必须要知道这个字节串是用什么字符编码的方式进行编码的。

如果知道了,就可以用字节串对象的decode方法 进行解码,参数指定了编码方式

比如

print(b'\xe4\xbd\xa0\xe5\xa5\xbd'.decode('utf8'))
print(b'\xc4\xe3\xba\xc3'.decode('gbk'))

上面的两行代码都可以解码出 字符串 ‘你好’

如果不小心写错了参数指定的编码方式, 就可能返回错误解码结果 , 比如

print(b'\xe4\xbd\xa0\xe5\xa5\xbd'.decode('gbk'))
返回 浣犲ソ

或者解码失败报错,比如

print(b'\xc4\xe3\xba\xc3'.decode('utf8'))

报如下错误:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte

上一页 下一页