UTF-8与GBK字符集解析
字符集的三个要素
- 字符表:要显示的字符的集合(例如所有的英文字符、所有的汉字)
- 字符编码:字符表中的字符对应的二进制表示
- 字符集:定义了一种规则,将一串二进制数字解释为一个字符
Unicode编码
Unicode是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。目前已经编码了12万+的字符。—— 维基百科
简单来说,Unicode就是给世界上存在的字符都赋予唯一的二进制编码。
Unicode直接做字符集的问题
因为Unicode要编码所有可能的字符,那么每个字符占用的字节长度就会变多。以英文为例,一个英文字符使用ASCII码只需要一个字节,而用Unicode需要4个字节,甚至更多。并且前面的字节都是0。这样纯英文文件的存储大小就会成倍扩大,是极大的浪费。
UTF-8编码
一种变长的编码方式,基于Unicode的一种实现。它使用1--4个字节表示一个字符,根据不同的字符变化字节的长度,可以节省空间。编码规则如下:
- 对于单字节的字符,字节的第一位设为0,后面7位是这个字符的unicode码。ASCII码表中的字符,UTF-8编码与其ASCII码保持一致。
- 对于n个字节的字符(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位均设为10。剩余的二进制位,从后向前填上这个符号的unicode码。用0填充未使用的二进制位。
Unicode范围 | 编码格式 | 剩余位数 |
---|---|---|
000000 – 00007F | 0xxxxxxx | 7位 |
000080 – 0007FF | 110xxxxx 10xxxxxx | 11位 |
000800 – 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx | 16位 |
010000 – 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 21位 |
根据上表可以看出,UTF-8剩余可以填的位数,决定了对应Unicode编码的范围。 下面举个转换的例子:
"樊"的unicode是6A0A(0110 1010 0000 1010),查表可知,6A0A属于第三行的范围,因此"樊"的UTF-8编码需要三个字节,即格式是 1110xxxx 10xxxxxx 10xxxxxx 。然后,从6A 0A的最后一个二进制位开始,从后向前填入格式中的x,多出的位补0。最终,"樊"的UTF-8编码是11100110 10101000 10001010(E6 A8 8A)
由此可以总结出字符用UTF-8编码的规律:
- 4个字节的UTF-8十六进制编码一定是以F开头
- 3个字节的UTF-8十六进制编码一定是以E开头
- 2个字节的UTF-8十六进制编码一定是以C或D开头
- 1个字节的UTF-8十六进制编码一定是以小于8的数字开头
注:UTF-8并没有编码所有的Unicode的字符,只包含了第0号平面(plane)和部分1号平面的字符。这属于更深层次的探究,感兴趣的读者可以通过UTF-8与Unicode字符平面映射了解。
中文编码
GB2312
该字符集使用2个字节表示一个字符。简单地理解,一个小于127的字节的意义与ASCII码相同,但两个大于127的字节连在一起时,就是GB2312编码的字符。以下是两个字节的具体范围:
第一个字节的范围是0xA1(161)–0xF7(247) ; 第二个字节的范围是0xA1(161)–0xFE(254)
共收录了6763个汉字,还包括拉丁字母、希腊字母、日文字符。并对 ASCII 里已有的数字、标点、字母赋予了两个字节的编码,这就是”全角”字符,而小于127的就称为”半角”字符。
GBK
由于GB2312仅包含了常用汉字,没有编码生僻字以及繁体字,GBK就对其进行了扩展。简单地理解,只要第一个字节大于127,不管后面的字节是否大于127,就是GBK编码的字符。以下是两个字节的具体范围:
第一个字节的范围是0x81(129)–0xFE(254) ; 第二个字节范围一部分在0x40(64)–0x7E(126),另一部分在0x80(128)–0xFE(254)
这样扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312 的所有内容,提供了23940个编码,使用了21886个。
中文编码的存在价值
UTF-8编码汉字通常需要三个字节,而GBK只需要两个字节,所以对于纯中文、不考虑国际化,且对流量和存储大小比较敏感的应用,可以使用GBK编码节省存储空间和传输流量。
参考资料
原博文发布在个人博客,欢迎访问!!