字符编码问题:Unicode 和 UTF-8

0.144字数 1736阅读 349

Unicode

Unicode 是一种编码,它将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码。这样乱码问题就会消失。这就是 Unicode,就像它的名字都表示的,这是一种所有符号的编码。
Unicode 是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样。

Unicode问题

Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字“ 金 ”的 Unicode 是十六进制数91D5,转换成二进制数足足有15位( 1001 0001 1101 0001),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题:

  • 第一个问题是:如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢? 比如这个“金”字, 二进制是 1001 0001 1101 0001 我们怎么知道他不是两个ascii 字符, 分别是10010001 和 11010001 ? 而是1001000111010001一个整体表示一个字符?
    所以就有这个问题, unicode 虽然定义了每个字符的唯一二进制编码, 但是那里是分隔符我们不确定, 我们不知道到底哪里是代表一个字符,还是两个字符,或者三个字符。所以必须有一些规则来定义这个分割符

  • 第二个问题是,有了第一个问题,我们很自然会想到, 自然没法区分怎么分割字符,那么干脆每个字符都用三个字节代表吧, 每三个字节就是一个字符, 一刀切,最妥当了。
    但是我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

还是以字来讲解, 的unicode码是91D1(16进制), 对应的二进制是: 1001 0001 1101 0001(二进制),它在unicode的第三个范围,0000 0800-0000 FFFF , 所以如果它要用utf-8来表示的话, 就要按找utf-8定义的规则 1110xxxx 10xxxxxx 10xxxxxx来转成utf-8的编码。
最后转换的UTF-8结果就是:11101001 10000111 10010001
而这个UTF-8的码是二进制的,转成16进制就是 e9 87 91 (十六进制)
然后转成我们平常python 打印字符时候显示的UTF-8字符 \xe9\x87\91
\x是个分隔符。

UTF-8 GBK UTF8 GB2312 之间的区别和关系

UTF-8:Unicode TransformationFormat-8bit,允许含BOM,但通常不含BOM。是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24为(三个字节)来编码。UTF-8包含全世界所有国家需要用到的字符,是国际编码,通用性强。UTF-8编码的文字可以在各国支持UTF8字符集的浏览器上显示。如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,他们无需下载IE的中文语言支持包。

GBK是国家标准GB2312基础上扩容后兼容GB2312的标准。GBK的文字编码是用双字节来表示的,即不论中、英文字符均使用双字节来表示,为了区分中文,将其最高位都设定成1。GBK包含全部中文字符,是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBD大。

GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:
GBK、GB2312--Unicode--UTF8
UTF8--Unicode--GBK、GB2312

因为unicode 定义所有字符都有唯一的二进制, 所以任何的编码转换都要转成unicode作为中介,然后再根据各个编码规则,自己转成自己的编码

总结

unicode 转成utf-8 步骤 :
1.查询到的unicode 是 91d1
2.91d1 在unicode符号范围 0000 0800-0000 FFFF 里面, 对应的utf-8规则是 1110xxxx 10xxxxxx 10xxxxxx
3.91d1转成二进制是: 10010001 11010001
4.然后将91d1 的二进制 10010001 11010001按规则转成utf-8的 11101001 1000 0111 1001 0001
5.utf-8的二进制 11101001 1000 0111 1001 0001 转成 utf-8的十六进制是 e1 87 91
6.所以最后 utf-8字符就是 \xe1\x87\x91

参考

字符编码笔记:ASCII,Unicode 和 UTF-8

推荐阅读更多精彩内容