字符集与字符编码
在解释字符集与编码问题之前,先谈一下之前我的理解。我对字符集和字符编码的理解,单纯来自于字面含义:字符集就是抽象字符的集合;字符编码就是把字符集中的字符转化之后的二进制序列;编码就是把字符转化为二进制的过程,解码就是把二进制转化为字符的过程。
其实上面的理解有些问题。估计很多人也是这么想的,也不影响编程。既然问题都提出来了,这里就进一步解释下吧。
准确解释
字符集与字符编码发展过程中,有过两个阶段:简单字符集;现代编码模型。
-
简单字符集
在简单字符集中,字符集与字符编码是同义词。字符集是一套系统,包含了抽象字符,以及最终的二进制序列。ASCII属于简单字符集。我猜想GB2312,GBK应该也属于简单字符集。
-
现代编码模型
在现代编码模型,把字符编码的概念细化:有哪些字符,字符的编号,编号如何编码成码元,二进制序列。把概念细化的目的是,创建一套能够用不同方式编码的通用字符集。
现代编码模型
在现代编码模型中,使用到了比“字符集”、“字符编码”更多,更准确的术语。现代编码模型分为5个层次。
-
抽象字符表,也就是所有抽象字符的集合。
-
编码字符集
把抽象字符表中的字符映射为1个坐标(整数值对:x,y)或者一个非负整数N,这个坐标或者非负整数称为码位值。我们这里这样理解:把抽象字符单行排列,那每个字符就对应一个非负整数N;把抽象字符排成矩阵,那每个字符就对应一个坐标。
编码字符集是由抽象字符表与其码位值组成的系统;即编码字符集 = 抽象字符表 + 所有码位值。
如果细究Unicode的概念,Unicode实际上是一个编码字符集。
-
字符编码表
在编码字符集中,一个抽象字符被映射成为一个码位值。把这个码位值再做一次映射,映射成为一个整数,或者一个整数序列。这样抽象字符表就映射成了字符编码表。
这里有两个问题,为什么要再映射一次?为什么有的码位值映射成了一个整数,有的码位值映射成了一个整数序列呢?
这两个问题原因相同,就是为了解决变长编码的问题。对于定常编码来说,直接让 码元=码位值 即可。 但是对于变长编码来说,映射就复杂一些。
变长编码,把一个码位值映射成为一个码元序列。这里很像我们的十进制数字,只有0~9个数字,要表示数值678的话,就需要6、7、8三个数字的序列。
Unicode有多种编码方式:
-
UTF-32是定常编码,每个抽象字符都对应4个字节,即每个字符对应一个码元,一个码元占用4个字节。
-
UTF-8是变长编码,每个码元占用1个字节,每个抽象字符对应一个码元序列,码元序列的长度是1或2或3或4,即每个抽象字符占用1到4个字节的存储空间。
-
UTF-16是变长编码,每个码元占用2个字节,每个抽象字符对应一个码元序列,码元序列的长度1或2,即每个抽象字符占用2个或4个字节的存储空间。
-
-
字符编码方案
把码元转化为二进制序列,这就是编码方案。
至此一个抽象字符就映射成了二进制序列。用一张图来表示:
字符“A”对应的Unicode值,以及各种编码及其编码占用存储空间如下:
Unicode 0x00000041 4个字节 UTF-8 0x41 1个字节 UTF-16BE 0x0041 2个字节 UTF-16LE 0x4100 2个字节 UTF-32BE 0x00000041 4个字节 UTF-32LE 0x41000000 4个字节
小结
之前提到的字面理解,我们把它修正下。
大多数情况下,字符集是指一整套系统,包括了抽象字符,码位值,码元,以及最终的二进制序列。
大多数情况下,字符编码与字符集是同义词。
编码,把字符转换为二进制序列;解码,把二进制序列转换为字符。
其实字符集中的术语问题,由于历史原因,含义是比较混乱的,所以我并没有对字符集以及字符编码给出准确的定义,只给了一个约定的叫法。如果理解了现代编码模型,即便别人说法与前面的术语不一致,我们也能明白别人的意思。
字符集与字符编码章节,来自于维基百科,我做了整理。
字符对应的Unicode以及utf编码,来自于链接:https://www.qqxiuzi.cn/bianma/Unicode-UTF.php