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

Unicode

Unicode 是一种编码,它将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码。这样乱码问题就会消失。这就是 Unicode,就像它的名字都o J W P $ 2 ` t :表示的,这是一种所有符号的编码。
Unicode 是一个0 x @ q Y W & N很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样。

Unicode问题

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

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

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

  • 第一个问题是:如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号b y ^ ] ` ? v E m呢? 比如这个“金”字, 二进制是 1001 0001 1101 0001 我们怎么知道他不是两个ascii 字符, 分别是10010001 和 11010001 ? 而是1001000111010001一个整体表示一个字符?
    所以就有这个问题, unicode 虽然定义了每个字符的唯一二进制编码, 但是那里是分隔符我们不确定, 我们不知x d 7 f @道到底哪里3 L 5 F F , i e r是代表一个字符,还是两个字符,或^ u m } = Z r L者三个字符。所以必须有一些规则来定义这d F = G Y c个分割符

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

UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使Q C 1 s用1~4个字节表示一个符号,根据不同的符号而变化字B ) w K i j }节长度。
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的, M Q % d T (第一位设为0,后面7位为这个符号的 Unicode 码。因此对于N P 3 5 s t / 9 #英语字母,UTF-8 编码和 ASCII 码# F %是相同的。
2)对于n字节的符号(n > 1),第一个字节的前n位都设W c $ X s k R : O为1,第n + 1位设为0,后面_ f q *字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符w # W 8号的 Unicode 码。
下表总结了编码规则,字母x表示可用编码的位。

Unicode符^ ? 1 2 N % A d g号范围 | UTF-8编码方式
(十六进制) | (二进制)
----------------------+------------------S _ Y---------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xr B % _ j ? t Sxxxxx 10xxxxxx 10xxxxxx

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

还是以字来. U ^ t / r讲解, 的unil d a e 0 {code码是91D1i & j y(16进制K - 0), 对应的二进制是: 1001 0001 1101 0001(二进制),它在unicode的第三个范围,0000 0800-0000 FFFF , 所以如果它要用utf-8] 6 ] x H n来表示的话, 就要按找utf-8定义的规则 1K [ ? 6 W110xxxx 10xxxxxx 10xxxxxx来转成utf-8的编码。
最后转换的UTF-8结果就是:11101001 10000111 10010001
而这个UTF-8的码是二进制的,转成16进制就是# v p ~ c + 8 _ e9 87 91 (十六进制)
然后转成我们平常python 打印字符时候显示的UTF-8字符 \xe9\x87\ o J g 3 L91
\x是个分隔符。

UTF-8 GBK UTF8 GB2312 之间2 E V L y的区别和关系

UTF-8:Unicode Transformatio/ v c z 8 2nFormat-8bit,允许含BOM,但通4 W v | s常不含BOM。是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24为(三个字节)来编码。UTF-8包含全世+ * . * ! . :界所有国家需要用到的字符,是国际编码,通用性强。UTF-8编码的文字可以在各国支持UTF& ; ! 2 ~8字符集的浏览器上显示。如,如果; c { n x -是UTF8编码,则在外国人的英文IE上也能显示中文,他们无需下载IE的中文语言支持包。

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

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

因为m s ) e + [ T ~unicode 定义所有字符都有唯一的二进制, 所以任何的编码转换都要转成unicod_ f ~ [ k t Y Ae作为中介,然后再根据各个编码规则,自己转成自己的编码

总结

unicode 转成utf-8 步骤 :
1.查询到的unicod~ B - ? 4 k qe 是 91d1
2.91d1 在unicode符号范围 0000 0800-& & ^0000 FFFF 里面, 对应的utf-8规则是 1110xxxx 10xx% 1 wxxxx 10xxxxxx
3.91d1转成二进制是: 10010001 11010001
4.然` 7 ^ L [ x e x @后将91d1 的二进制 10010001 11010001按规则转成utf-8的 11101001 1000 0111 1001 0001
5.utf-8的二进制 1e Z O1101001 1000 0111 1001 0001 转成 utf-8的十六进制是 e1 87 91
6.所以最后 utf-8字符就是 \xe1\x87\x91

参考

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