RTC程序设计:实时音视频权威指南
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.3.2 Unicode与UTF-8

上一节介绍了GB编码,与之对应,各国也有各自的文本编码标准。图1-14显示了各种编码标准的衍生关系。为了有一种统一的编码标准,1990年,联合国经济社会文化组织(ECOSOC)开始制定Unicode编码标准。

img

图1-14 各种编码标准的衍生关系

通过Unicode官网可以看到,截至2022年9月13日,共发布了15个版本。

Unicode有1 114 112(0x110000)个码位,分为17个字符平面,每个平面有65 536个码位。

Unicode 7.0标准共收录字符112 956个,其中汉字74 616个。

对于同一个Unicode码位,通常有3种编码方式:UTF-8、UTF-16、UTF-32。UTF-32编码总是使用4字节,相邻的编码具备连续性。UTF-16编码总是使用2字节,且在0平面与UTF-32相等。

Windows平台通常使用UTF-16编码,而macOS平台通常使用UTF-32编码。

0平面为基本位平面(Basic Multilingual Plane,BMP),码位从0x0000到0xFFFF。

Unicode为亚洲文字保留了CJK(Chinese Japanese Korean)区域,从0平面的0x4E00开始,共包含20 912个汉字。还有5个A~E的扩展区域,其中CJK A扩展区域位于0平面,从0x3400开始,扩展区域B~E位于2平面。

在0平面的0xD800和0xDC00开始的地方,各保留了1 024个码位,被称为UTF-16替代区(UTF-16 Surrogate Codec),用来转义1~16平面中的字符。这样大于2字节的字符,也能在UTF-16编码下进行表示。

1平面为补充位平面(Supplementary Multilingual Plane,SMP),码位从0x10000到0x1FFFF。

平面3~14中的很多码位都尚待分配。

最后的15、16平面为私人使用区,用户可以自行定义,被称为PUA(Private Use Area)-A、PUA-B。

在Windows平台上,可以使用如下两个API进行Unicode与GB编码之间的互转。

img

在UNIX平台上,我们通常使用libiconv开源库来完成字符集之间的转换。

UTF-8编码

Unicode用来表示全球的文本是足够的,但它的问题是,当它用来表示英文的时候,太浪费了。

英文字符只需要128个码位就足够了,于是1992年,UTF-8编码被UNIX系统的发明人Ken Thompson发明出来。

UTF-8编码使用1~6个变长字节来表示1个字符。

当使用1字节时,它与ASCII码完全一致,即0x00~0x7F,形如二进制0xxxxxxx,这里字母x代表0或1。

当使用2字节时,可以表示0x80~0x07FF的码位,形如110xxxxx 10xxxxxx可以表示8~11比特。

当使用3字节时,可以表示0x0800~0xFFFF,形如1110xxxx 10xxxxxx 10xxxxxx,可以表示12~16比特,这能表示所有2字节的编码。由于常用汉字都位于0平面的CJK和CJK A中,因此大多数汉字也能用3个UTF-8编码表示。

当使用4字节时,其位序列为11110xxx 10xxxxxx 10xxxxxx 10xxxxxx,可以表示21比特,表示范围是0x10000~0x1FFFF,这是Unicode 6.1的标准。

其余更大的UTF32字符,则使用5字节或6字节的UTF-8编码。

Unicode的文件,通常会在最前面加上3字节的BOM(Byte Order Mark)头,来表示文本的编码与字节序。

对于UTF-8编码,BOM通常为0xEF 0xBB 0xBF。为了能让C++源码跨平台显示与编译,我们的.h/.cpp文件都必须加上UTF-8的BOM头。

Windows平台上提供的字符集转换API也可以用于UTF-8编码的转换。

但由于UTF-8编码相对容易清晰,自己实现一套UTF-8与UTF-16的转换函数也是很方便的。

以下函数实现了对一个2字节字符的UTF-8编码,同时返回其需要的UTF-8字节数。

img

读者可以将上述代码作为参考,并实现对应UTF-32字符的编解码函数,以及对一个连续Unicode字符串的UTF-8转换[15]

下一节将展示一个显示文本对应编码的工具。