ICU以及字符编码的介绍
[1] ICU编程接口的文档:http://userguide.icu-project.org/
[2] UTF8编码介绍:http://zh.wikipedia.org/wiki/UTF-8
[3] 字符集GBK和UTF8的区别说明:http://blog.itpub.net/55022/viewspace-713901
项目中,我需要压力测试一段ICU封装函数的代码,即找到一段GBK编码出错,UTF8编码成功的字符序列;和一段GBK编码,UTF8编码都出错的字符序列。
以前对编码一知半解的我,甚至认为unicode就是utf8。。。
1、 unicode就是用2个字节表示全球所有的字符,也就是每个字符都是2个字节。MFC的_T()就是把字符串用unicode编码,然后在不同的操作系统平台上转换成不同的编码显示方式,适应软件的全球化。
2、 ASCII是最简单的编码方式,字节高位为0,只有1个字节。在unicode下,ASCII的字符也是2个字节的,但是洋人为了节约自己的存储空间、减少传输容量等,就设计了UTF8的编码。
3、 UTF8编码是与unicode一一对应的编码方式,在UTF8下,ASCII字符是1个字节的,但是中文却变成了3、4个字节。然后中国人又不愿意了,设计了GBK编码,使中文用2个字节编码表示,这是后话了。
这是unicode/UTF8 之间的转换关系如下:
unicode(U+) | UTF8 |
U+00000000 - U+0000007F: | 0xxxxxxx |
U+00000080 - U+000007FF: | 110xxxxx10xxxxxx |
U+00000800 - U+0000FFFF: | 1110xxxx10xxxxxx10xxxxxx |
U+00010000 - U+001FFFFF: | 11110xxx10xxxxxx10xxxxxx10xxxxxx |
U+00200000 - U+03FFFFFF: | 111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx |
U+04000000 - U+7FFFFFFF: | 1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx |
比如: "我" 的unicode编码为 "U+6211"(01100010 00010001),在U+00000800 - U+0000FFFF之间,所以采用三字节编码,按规则分段为:0110 001000 010001,再分别替换上表中的x,得到11100110 10001000 10010001,即为 "E6 88 91",这就是 "我" 的UTF-8编码。
4、 GBK用2个字节表示中文字符,1个字节表示ASCII字符。也就是用了UTF8类似编码方式的简化版,规定中文最高位都为1,ASCII最高位都为0。当用GBK解码时,若高字节最高位为0,则用ASCII码表解码;若高字节最高位为1,则用GBK编码表解码。
一开始,我怎么也找不到GBK编码失败,UTF8编码成功的方法,基本已经打算放弃,因为GBK编码把多字节的UTF8字符分割成了两个两个的单元,强行进行了编码。但是当我看到“GBK的整体编码范围是为0x8140-0xFEFE,不包括低字节是0x7F的组合。高字节范围是0×81-0xFE,低字节范围是0x40-7E和0x80-0xFE”,我重新燃起了希望,这简直就是留了GBK与UTF8编码区别的后门。
比如这句:
char pMData[11] = {'a', 'b', 'c', '\xE6', '\x88', '\x91', '\x7F', 'd', 'e'};
UTF8编码时把它分为('\xE6', '\x88', '\x91')和('\x7F'),而GBK把它分成了('\xE6', '\x88')和('\x91', '\x7F'),而('\x91', '\x7F')导致了GBK编码的失败。
再比如这句:
char pMData[11] = {'a', 'b', 'c', '\xEE', '\xEE', '\xEE', '\x7F', 'd', 'e'};
UTF8编码将其分为('\xEE', '\xEE', '\xEE'),('\x7F'),其中('\xEE', '\xEE', '\xEE')的第一个字符为E,其编码格式应该为1110xxxx10xxxxxx10xxxxxx,即第3个字符只可能为8,9,A,B,而不可能是E(画红色背景的那个字符),因而UTF8编码失败了。而GBK把它分成了('\xEE', '\xEE')和('\xEE', '\x7F'),而('\xEE', '\x7F')导致了GBK编码的失败。