首先明确一点:
UFT-8是编码方式
Unicode是字符集
U n i c o d e \color{red}{Unicode} Unicode
字符集,如ASCII字符集
97—‘a’
98—‘b’
Unicode 则是
U+2074—‘4’
U+2075—‘5’
Unicode 表示的范围:U+0000 to U+10FFFF (十六进制)
2^21=xxx 我就不具体算了,但足以看出和ASCII完全不是一个量级的
原本Unicode 就是为了解决ASCII 不够用的情况而发明的
(全球化,中文,日文,等等 Unicode—Universal )
但实际上,Unicode 出现了“性能过剩”的情况-----Unicode码还有挺多空着没用的
U n i c o d e 中 还 有 字 符 来 表 示 易 经 中 的 八 卦 符 号 。 。 。 \color{blue}{Unicode 中还有字符来表示易经中的八卦符号。。。} Unicode中还有字符来表示易经中的八卦符号。。。
尽管如此,还是有空着的Unicode码!牛逼牛逼~
大家可以到这个网站去看看链接
表示的多了,需要的空间也就多
完整覆盖unicode 需要4字节的数据
而ASCII码只需要1字节
我们需要一个折中的办法~
然后就有了像UTF-8 这样的编码方式来合理、高效地使用Unicode 码
字 符 集 与 编 程 语 言 \color{red}{字符集与编程语言} 字符集与编程语言
科学家发现,用2字节的Unicode 就足够全球的用户日常使用了~
2字节,16位,2^16=65536
别觉着少,前面说了,是日常使用,我们中国日常使用的汉字都大概只有3500个左右
如此一看60000真的够了
Java 里的char类型就是2字节,原因就是采用了Unicode的字符集
C语言中char 占1字节,采用的是ASCII的字符集,有0~127 共128个字符
你可能会问,为什么1字节,2^8=256,为啥表示范围只有0~127
因为。。这C语言美国人发明的,对他们来说,128个已经足够表示所有英文字母和很多特殊符号了
(当然,后来有了拓展的ASCII,可以参考这篇文章:在C语言中输出拓展的ASCII)
U T F − 8 \color{red}{UTF-8} UTF−8
首先,UTF-8 可变字节,可以用1字节表示,也可以用2字节表示,还可以3字节,4字节
UTF-8:
1 byte: Standard ASCII (标准ASCII)
2 bytes: Arabic, Hebrew, most European scripts (most notably excluding Georgian)(多国的语言)
3 bytes: BMP(Basic Multilingual Plane 基本多文种平面)
4 bytes: All Unicode characters(所有Unicode 字符)
B M P \color{blue}{BMP} BMP
上面还需要补充介绍的就是BMP(Basic Multilingual Plane 基本多文种平面)了
前面提到过,Unicode 的范围:U+0000 to U+10FFFF (16进制)
10FFFF 前面的 “10” 是用来标识平面(Plane)的
十六进制的“10”转化成十进制就是16
0~16,则Unicode 总共有17个Plane(平面)
而BMP 就是第一个编号为0的平面
这个平面上的字符,就是我们上面提及的足够我们日常使用的一个平面
(一个平面Plane有两字节的空间-----联想一下Java的2字节char)
有人可能会问了,UTF-8 是怎么实现可变字节数的呢?
举个例子:
\xe2\x81\xb4
我怎么知道上面这UTF-8的字符串到底表示一个Unicode还是两个,还是三个?
这就涉及到UTF-8 的编码规则了
编 码 规 则 \color{red}{编码规则} 编码规则
(二进制,8位为一字节)
一个字节的UTF-8(0开头): 0xxxxxxx
两个字节的UTF-8(开头两个1加0,另一字节开头是10):110xxxxx 10xxxxxx
三个字节的UTF-8(开头三个1加0,另两字节开头也是10):1110xxxx 10xxxxxx 10xxxxxx
四个字节的UTF-8(开头四个1加0,另三字节开头也是10):11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
现在回到刚刚的字符串
\xe2\x81\xb4
把十六进制转到二进制
11100010 10000001 11000100
可以看到在第一个字节中,开头是三个1加0
则表示这是三个字节的UTF-8
则 “\xe2\x81\xb4” 一起只表示一个Unicode码
具体对应哪个Unicode吗呢?
再接着看
U T F − 8 到 U n i c o d e , 解 码 \color{red}{UTF-8到Unicode,解码} UTF−8到Unicode,解码
把转化出来的二进制串对应编码规则中的模板
11100010 10000001 10110100
1110xxxx 10xxxxxx 10xxxxxx
xxxx对应上去,我们得到:
1110xxxx 10xxxxxx 10xxxxxx
0010 000001 110100
把上面得到的新串每四位为一个单元分开则有:
0010 0000 0111 0100
转化成16进制:2074
则 “\xe2\x81\xb4” 对应的Unicode码为 U+2074
具体表示什么字符,就可以查表了~
上 面 介 绍 的 就 是 所 谓 解 码 d e c o d e ( ) 的 操 作 \color{blue}{上面介绍的就是所谓解码decode()的操作} 上面介绍的就是所谓解码decode()的操作
U n i c o d e 到 U T F − 8 , 编 码 \color{red}{Unicode到UTF-8,编码} Unicode到UTF−8,编码
进行编码时,对Unicode码也有一套规则
0x00000000 - 0x0000007F:
0xxxxxxx
0x00000080 - 0x000007FF:
110xxxxx 10xxxxxx
0x00000800 - 0x0000FFFF:
1110xxxx 10xxxxxx 10xxxxxx
0x00010000 - 0x001FFFFF:
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
不同范围的Unicode 码,对应不同字节的UTF-8
像刚刚的U+2074,范围就在 0x00000800 - 0x0000FFFF
则对应3字节的UTF-8,知道使用哪个模板后
把Unicode 码转化成2进制,然后填进xxxx的位置就好了~
(就把解码的工作逆着来一遍就好了)
U T F − 8 与 U T F − 16 , U T F − 32 \color{red}{UTF-8与UTF-16,UTF-32} UTF−8与UTF−16,UTF−32
UTF-8 之所以为8,是因为它以8比特(一字节)为一个基本单元
UTF-16 则是以16比特(2字节)为一个基本单元
UTF-32 同理
对于UTF-16
和UTF-8 一样,也有一套编码规则:
两字节的UTF-16:xxxxxxxxxxxxxxxx
四字节的UTF-16:110110xxxxxxxxxx 110111xxxxxxxxxx
Unicode:
范围1.U+00000000 - U+0000D7FF xxxxxxxxxxxxxxxx
范围2.U+0000E000 - U+0000FFFF xxxxxxxxxxxxxxxx
范围3.U+00010000 - U+0010FFFF 110110xxxxxxxxxx 110111xxxxxxxxxx
细心的朋友可能会发现,上面Unicode 的范围1和范围2并不是连续的
D7FF转到二进制是1101 1111 1111 1111
没错
正好对应范围三中的 110110xxxxxxxxxx
这也就是UTF-16 实现可变字节的手段~
(这里我就不细说了,大家稍微动动脑筋就明白为什么空开一段就能让UTF-16实现变字节)
需要补充的是空开的那一段,U+D800 - U+DFFF
维基百科上是这么描述的(这里是链接):
The Unicode standard permanently reserves these code point values for UTF-16
encoding of the high and low surrogates, and they will never be assigned a character,
so there should be no reason to encode them.
The official Unicode standard says that no UTF forms, including UTF-16, can encode these code points.
大意就是说那一段的Unicode 就是为UTF-16空着的,不会设置有效字符
所以大家就不用顾虑啦~
其实那一段空着并不是浪费的,详细的我这也不展开了
有兴趣了解的朋友,就上面那个维基百科的链接有详细介绍
小标题是:Code points from U+010000 to U+10FFFF
大意就是UTF-16把那空着的段又分成了两段:
0xD800–0xDBFF(high surrogate) 和 0xDC00–0xDFFF(low surrogate)
分别对应UTF-16四字节的规则中的前两字节和后两字节
两两组合出来了UTF-16后面绝大部分的Unicode:U+00010000 - U+0010FFFF
UTF-32
这就没有什么可变字节了
直接32位四字节硬怼
总结:
Unicode 是为了应对 ASCII字符集不够用而发明的
而直接用4字节去表示Unicode 又容易浪费资源
所以有了UTF-8、UTF-16 这样的编码方式
对了还得补充一点
对于亚洲的一些文字,例如说我们的中文
用UTF-8需要3字节
而用UTF-16则只需要2字节
但是,互联网中普遍都是用UTF-8
因为,互联网的语言是英文。。。