字符集与字符编码-Unicode、GB2312、UTF

现代编码模型

由统一码和通用字符集所构成的现代字符编码模型将字符编码的概念分为:有哪些字符、它们的编号、这些编号如何编码成一系列的“码元”(有限大小的数字)以及最后这些单元如何组成八位字节流。在Unicode Technical Report (UTR) #17中,现代编码模型分为5个层次。

抽象字符表(Abstract character repertoire)

抽象字符表(Abstract character repertoire)是一个系统支持的所有抽象字符的集合。字符表可以是封闭的,即除非创建一个新的标准(ASCII和多数ISO/IEC 8859系列都是这样的例子),否则不允许添加新的符号;字符表也可以是开放的,即允许添加新的符号(统一码和一定程度上代码页是这方面的例子)。特定字符表中的字符反映了如何将书写系统分解成线性信息单元的决定。

编码字符集(CCS:Coded Character Set)

编码字符集(CCS:Coded Character Set)将字符集C中每个字符映射到1个坐标(整数值对:x, y)或者表示为1个非负整数N。字符集及码位映射称为编码字符集。例如,在一个给定的字符表中,表示大写拉丁字母“A”的字符被赋予整数65。多个编码字符集可以表示同样的字符表,例如ISO-8859-1和IBM的代码页037和代码页500涵盖同样的字符表但是将字符映射为不同的整数。由此产生了编码空间(encoding space)的概念:简单说就是包含所有字符的表的维度。可以用一对整数来描述,例如:GB 2312的汉字编码空间是94 x 94。可以用一个整数来描述,例如:ISO-8859-1的编码空间是256。也可以用字符的存储单元尺寸来描述,例如:ISO-8859-1是一个8比特的编码空间。编码空间还可以用其子集来表述,如行、列、面(plane)等。编码空间中的一个位置(position)称为码位或码点(code point)。一个字符所占用的码位称为码位值(code point value)。1个编码字符集就是把抽象字符映射为码位值。

字符编码表(CEF:Character Encoding Form)

字符编码表(CEF:Character Encoding Form),也称为”storage format”,是将编码字符集的非负整数值(即抽象的码位)转换成有限比特长度的整型值(称为码元code units)的序列。这对于定长编码来说是个到自身的映射(null mapping),但对于变长编码来说,该映射比较复杂,把一些码位映射到一个码元,把另外一些码位映射到由多个码元组成的序列。例如,使用16比特长的存储单元保存数字信息,系统每个单元只能够直接表示从0到65,535的数值,但是如果使用多个16位单元就能够表示更大的整数。这就是CEF的作用,它可以把Unicode从0到140万的码空间范围的每个码位映射到单个或多个在0到65,5356范围内的码值。最简单的字符编码表就是单纯地选择足够大的单位,以保证编码字符集中的所有数值能够直接编码(一个码位对应一个码值)。这对于能够用使用八比特组来表示的编码字符集(如多数传统的非CJK的字符集编码)是合理的,对于能够使用十六比特来表示的编码字符集(如早期版本的Unicode)来说也足够合理。但是,随着编码字符集的大小增加(例如,现在的Unicode的字符集至少需要21位才能全部表示),这种直接表示法变得越来越没有效率,并且很难让现有计算机系统适应更大的码值。因此,许多使用新近版本Unicode的系统,或者将Unicode码位对应为可变长度的8位字节序列的UTF-8,或者将码位对应为可变长度的16位序列的UTF-16。

字符编码方案(CES:Character Encoding Scheme)

字符编码方案(CES:Character Encoding Scheme),也称作”serialization format”。将定长的整型值(即码元)映射到8位字节序列,以便编码后的数据的文件存储或网络传输。在使用Unicode的场合,使用一个简单的字符来指定字节顺序是大端序或者小端序(但对于UTF-8来说并不需要专门指明字节序)。然而,有些复杂的字符编码机制(如ISO/IEC 2022)使用控制字符转义序列在几种编码字符集或者用于减小每个单元所用字节数的压缩机制(如SCSU、BOCU和Punycode)之间切换。

传输编码语法(transfer encoding syntax)

传输编码语法(transfer encoding syntax),用于处理上一层次的字符编码方案提供的字节序列。一般其功能包括两种:一是把字节序列的值映射到一套更受限制的值域内,以满足传输环境的限制,例如Email传输时Base64或者quoted-printable,都是把8位的字节编码为7位长的数据;另一是压缩字节序列的值,如LZW或者行程长度编码等无损压缩技术。

ASCII

ASCII含有128个字符,包括基本拉丁字母、阿拉伯数字和英式表达点符号以及33个控制字符。其编码字符集将128个字符映射到0-128的整数范围内,编码空间为128。字符编码表直接采用码点值作为码元即可。字符编码方案同样直接将码元以二进制表示得到8位字节即可。

GB 2312

GB 2312收录了6763个汉字,也收录了拉丁字母、希腊字母等682个其它字符。其编码字符集将字符映射到(区,位)形式,每区含有94个字符、共计94个区,即编码空间为94 x 94。字符编码表包含国标码(交换码)与内码(机内码)两种。国标码将区码、位码分别加32得到一组新的表示,避开了ASCII中的不可显示字符(0-32),因此得到范围(33,33)-(126,126)。显然,国标码与ASCII码冲突,因此将国标码的区码、位码再加128得到新的范围,此时的的区码、位码字节均不与ASCII冲突。字符编码方案通常将机内码的区码部分作为高字节,位码部分作为低字节,成为2个字节,由此进行存储。

GBK与GB 18030

GBK在GB2312的基础上进行了扩展,额外收录了一些字符。GB 18030则在GBK的基础上进一步扩展,同时支持了4个字节的编码。

Unicode

Unicode是个正在发展中的字符集与字符编码标准。其抽象字符表正在不断扩充。其编码字符集将字符映射到(组,面,行,点)空间内。Unicode的编码字符集与ISO 10646(UCS)一致。组这一级别实际上并未使用,也不会使用。所以可以理解为(面,行,点)三元。当前共有17个平面,其中0号平面(U+0000 - U+FFFF)称为基本多文种平面,包含绝大多数常用的字符。其它平面称作辅助平面。Unicode字符编码表则称为Unicode转换格式(Unicode Transformation Format,简称为 UTF),常见的UTF包括UTF-8、UTF-16等。Unicode字符编码方案则在字符编码表的基础上附加了大端、小端等选择,将Unicode字符表示为字节流。

Unicode字符编码表(UTF-8、UTF-16)

UTF-8采用8位码元对Unicode码点进行表示,对于ASCII字符只需要1个字节即可表示,Unicode中的其它字符则使用2-6个字节进行编码。在字符主要为ASCII字符的情况下较节省空间。UTF-16采用16位码元对Unicode码点进行表示。对于基本多语言平面中的字符,使用UTF-16可以直接表示为1个码元,而对于辅助平面中的字符,则利用基本多语言平面中未编码为字符的代理区构成2个码元的代理对进行表示。

Unicode字符编码方案(BOM、大端序、小端序)

在UTF-16方案下,每个码元由两个字节构成。由此引入了大端、小端的问题:码元中的两个字符在存储或传输时使用以什么顺序进行?高位在前还是低位在前?以此为依据,UTF-16又可以细分为UTF-16LE和UTF-16BE。为了便于区分文件中的UTF-16编码使用大端序还是小端序,可以在文件开头放置一个标志,称为Byte Order Mark(BOM)。引入BOM后,又可以是否有BOM进一步划分为带BOM的和不带BOM的。理论上讲,使用UTF-8编码的情况下不存在大端序与小端序的问题,但是部分实现中仍然会在UTF-8文件中添加BOM。

UCS、UCS-2、UCS-4

UCS与Unicode是两个不同的标准,但是互相兼容,使用相同的编码字符集。UCS-2使用16位码元,因此可以表示基本多文种平面中的所有字符。与UTF-16标准不同的是,UCS-2无法支持辅助平面中的字符。UCS-4则使用32位码元,从而实现了Unicode字符集中的所有字符的表示。

抽象字符表之上

实质上,抽象字符表并不能代表所有渲染为单个字符的效果。在实际使用中,也有多个抽象字符组合成为渲染时的一个单位的场景。例如:不同国家的国旗 emoji 就由两个字符组合后渲染为单个 emoji 进行显示,将其中的一个码位删除后仍然可以展示为一个 emoji 。过去朋友圈等场景中可见的“击穿地板”等搞怪文字便是通过组合多个注音字符,在展示时本不应支持的组合被直接组合后达成这类超高的文字效果(组合字符)。

参考资料