程序员里面无人不知无人不晓的编码方案, 全称 American Standard Code for Information Interchange, 这个就不用多解释了, 一个字节编码一个字符, 虽然实际上只是用了7位就把128个字符给编进去了. 后来又出了个EASCII(Extended ASCII)把8位全用上了, 一共256了字符, 相比ASCII多了一些奇奇怪怪的字符. ASCII应该是研发最先知道的最简单的编码方案, 这里也不做过多介绍了.
ASCII提出的时候, 并没有考虑到其他国家如中日韩的字符. 仅凭一个字节, 只能编码256个字符, 很多国家的字符都没有. 随着计算机的普及, 各个国家都提出了自己的编码方案, 这些方案大同小异, 基本套路就是兼容ASCII, 且用两个字节来编码其他字符, 比如GB2312, BIG5这类编码方案, 但这些方案都有一个很明显的问题: 各自为战. 也就是说他们兼容ASCII, 编了本国语言, 其他的语言不管, 因此这些编码方案只能容许电脑处理双语环境(拉丁字母+本国语言), 不支持多语环境(多种语言混合), 比如GB2312就没有对阿拉伯语的支持, 如果一行字符里有中文, 英文和阿拉伯文, GB2312肯定编码不了.
Unicode就是为了解决传统编码方案的局限性而产生的, 在说Unicode之前, 首先需要了解的是现代编码模型.
现代编码模型将字符编码的概念分为了几个层次.
即一个系统支持的所有抽象字符的集合, 这个集合中包含了所有的抽象字符, 比如"中"是一个字符, 但是这个字到底是黑体还是宋体, 字号多少, 抽象字符表并不管, 有些字符甚至不可打印, 比如我们常见的"\n". 抽象字符表只描述这个系统支持的抽象字符.
字符表可以是封闭的, 即不允许添加新符号, 如ASCII的字符表, 而Unicode的字符表则是开放的字符表, 允许添加新的符号.
将字符集中的每一个字符映射到一个坐标或者一个非负整数, 字符集加上映射关系称为编码字符集, Unicode就是一个编码字符集. 既然是将字符集中的字符映射到另一个东西上, 那么就产生了编码空间的概念, 编码空间简单来讲就是包含所有字符的表的维度, 可以用整数, 坐标或者行, 列, 面等方式描述. 编码空间中的一个位置称为码位(code point)
将编码字符集的码位转换成有限比特长度的整型值(码元code units)的序列, 这对于定长编码如UCS-2来说是个到自身的映射, 但对于变长编码如UTF-8来说, 该映射比较复杂, 把一些码位映射到一个码元, 把另外一些码位映射到由多个码元组成的序列. 最简单的字符编码表就是单纯地选择足够大的单位, 以保证编码字符集中的所有数值能够直接编码(一个码位对应一个码值). 这对于能够用使用8 bit组来表示的编码字符集是合理的, 对于能够使用16 bit来表示的编码字符集(如早期版本的Unicode)来说也足够合理. 但是, 随着编码字符集的大小增加(现在的Unicode的字符集至少需要21位才能全部表示), 这种直接表示法变得越来越没有效率, 并且很难让现有计算机系统适应更大的码值.
将code units映射到8位字节序列, 以便编码后的数据的文件存储或网络传输. 在使用Unicode的场合, 使用一个简单的字符来指定字节顺序是大端序或者小端序(但对于UTF-8来说并不需要专门指明字节序).
用于处理上一层次的字符编码方案提供的字节序列. 一般其功能包括两种: 一是把字节序列的值映射到一套更受限制的值域内, 以满足传输环境的限制, 例如Email传输时Base64, 都是把8位的字节编码为7位长的数据;另一是压缩字节序列的值,如LZW或者进程长度编码等无损压缩技术.
Unicode在最初提出的时候, 认为只需要2字节就能容纳全部现代字符, 然而实际上编码了许多稀奇古怪的字符, 所以现在的Unicode编码空间为0x0-0x10FFFF, 至少需要21位来描述, 略小于3个字节.
我偶尔会看到"一个Unicode字符占用4字节的言论", 实际上Unicode作为一个编码字符集, 它没有一个字符占用多少字节这种概念, 因为它的作用是将字符映射到码位值, 这些码位值分布在0x0-0x10FFFF里, 它所占用的字节数, 和Unicode无关, 只和实际使用的字符编码方案有关. 例如UCS-4中一个字符占用4字节.
Unicode将编码空间划分为17个平面(plane), 从0到16. 0号平面称为基本多文种平面(BMP), 其他的16个平面可以统称为辅助平面(Supplementary Plane, SP).