0%

编码那些事儿

软件开发中,编码是一件很重要的工作,它涉及到了数据的传输与读取等方面。今天介绍下编码相关的知识。

ASCII

ascii码是用0-127这些状态位(即00000000-01111111)表示数字、字母、特殊符号等字符的编码规则,即用8个比特位(1个字节)表示最常用、基础的字符(例如:大写字母 W 用 01010111 表示,转换为十进制就是87,转换为十六进制就是 0x57)。ascii编码刚被创造时,使用计算机的人还不是很多,所以它能满足人们的需求。但是随着技术的进步与发展,科学家们发现ascii码已经不能满足需求了,很多其他国家的文字、符号并不能在计算机上被表示出来,于是将表示范围从127扩大到了256,即新增了128~256这些状态位来表示其他的文字或者符号,这些被称为扩展字符集。

GBK

等到计算机技术传入中国时,我们发现还没有用于表示汉字的状态位,这是不能容忍的。于是勤劳的中国人民创造了GB2312编码,GB2312编码中规定0~127的状态位与原来意义相同,称为”半角”字符,从127以后使用两个字节表示一个汉字。由于中华文化博大精深,随着计算机的普及,GB2312编码也不能满足人们的要求了,随后有相继扩展出了GBK和GB18030编码。GBK是采用单双字节变长编码,英文使用单字节编码,兼容ASCII字符编码,中文则采用双字节编码。

Unicode

首先得知道一点:Unicode 包含两个方面:1. 字符集 2. 编码方式

字符集

随着计算机在全世界的发展,如果世界各地都使用自己的编码规则,则会阻碍计算机的发展,导致世界不能互相交换信息,这时候Unicode通用字符集就出现了。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码(说白了就是一个数字编号),以满足跨语言、跨平台进行文本转换、处理的要求。Unicode使用两个字节表示一个字符。每个字符都有一个唯一的 Unicode 编号,这个编号一般用十六进制表示。

python3 中,可以使用 encode() 方法对字符串进行编码:

1
2
3
s1 = '马'
s1.encode('unicode_escape')[2:]
b'9a6c'

可以看到 ‘马’ 对应的 Unicode 编码是 9a6c,转换成二进制就是 1001 1010 0110 1100。

编码方式

Unicode 规定了每个字符对应的编号是多少,但是它没有说明这些编号如何存储。

UTF-8是Unicode字符集的一种实现方式,它规定了如何对 Unicode 字符的编号进行存储(即以何种方式保存 Unicode 字符的编号,保存这些编码是为了能够在网络中传输),它使用一个到四个不等的字节对一个字符进行编码,编码以后再存储。UTF-8可以表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII兼容。通过变长,UTF-8可以节省数据的空间。Unicode 的编号范围与 UTF-8 对应的二进制格式:

编号范围 二进制格式
0x00 - 0x7F(0 - 127) 0XXXXXXX
0x80 - 0x7FF (128 - 2047) 110XXXXX - 10XXXXXX
0x800 - 0xFFFF (2048 - 65535) 1110XXXX 10XXXXXX 10XXXXXX
0x10000 - 0x10FFFF (65536及以上) 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX

我们保存在内存中的数据都是 Unicode 编码,只有存储到硬盘上或者在网络传输中,才把 Unicode 编码转换成 UTF-8、GBK或者其他编码。

Python3中的编码

在 python3 中,有文本字符串类型(str对象)和字节字符串类型(byte对象)两种字符串,str类型的对象都是 Unicode,因此对于 str 类型的对象只有encode()方法,没有decode()方法(若运行,会报错)。byte对象是由str类型的对象使用 encode() 方法产生的,byte 对象可以进行解码,从而得到真正的数据。

1
2
str.encode(encoding="utf-8", errors="strict"):将 unicode 字符串转换为 byte 字节流
bytes.decode(encoding="utf-8", errors="strict"):将 byte 字节流转换为 unicode 字符串