转载需注明原地址,谢谢
目标:彻底弄懂字符集、编码字符集、字符编码集、unicode、utf8、utf16
1.什么叫字符集。
答:比如中文就可以叫汉子字符集,英文也可以叫英文字符集,总之就是指的一套字符的集合。
2.什么叫编码字符集
答:比如 我们规定 0 代表 我,1代表你,等等。 我们对字符集进行编码,一个字符对应一个整数序号(code point),这样集合就叫编码字符集。
其中较为出名的有:unicode、ascii。
3.什么叫字符编码集
首先讲讲为什么字符编码集的来历。
有了编码字符集后,下一步就是把字符的 code point 映射到计算机中。
常见的如ascii编码集,字符编码集中的数字与编码字符集中的数字字符一一对应。
然而ascii只有127个code point,当然可以完美表示。
而unicode有理论上有U+10FFFFcode point,
如果采取一一对应的方式,那么ascii表示需要1个字节的字符到unicode上需要3个字节。
而实际开发中,ascii的使用频率远远高于其他unicode字符,为了兼容其他字符,就让内存扩大3倍,所以这种一一对应的方式是不可取的。
那么如何选择一个合适的编码方案呢?
- 1.首先字符编码集应该是变长的,且越是高频的字符越是含的字节少,这样可以最大程度上优化使用内存。
- 2.其次,最好能够兼容一部分字符集。
综上考虑:
诞生了UTF系列和UCS系列编码
其中UTF分为UTF-8,UTF-16,UTF-32分别代表着用8位,16位,32位来代表某个单个code point。
其中UTF8和UTF16最为常用。
4.unicode
1.万国码。与ascii兼容
2.分成17区域,每个区域我们称为一个平面,其中每一个平面包含65536(0xFFFF)个code point,第一个平面 0U+FFFF,第二个平面U+10000U+1FFFF,以此类推。前两位是编号,范围在0x0~0x10之间,后4位为代码点。
3.最常见的是第一个平面,这个平面被称为 多语言平面(BMP)
4.unicode分成utf和ucs系列编码。
5.如何判断大小端?
什么叫大小端? 大端含义,从左往右读(常见),小端,从右往左读。http://www.ruanyifeng.com/blog/2016/11/byte-order.html
unicode规定:
那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?
Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1。
如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。
注意:这个规定是针对文件而言。实时上对于字节流而言,这没什么意义。
5.utf-8
1.变长,兼容ascii
首位0:表示1字节
首位110:表示2字节
首位1110:表示3字节
首位11110:表示4字节
….
10表示当前字节不是首位,为中间字节。
这里有个细节,为什么要中间字节为10而不是0呢?
如果用0表示,相同的字节可以表示更多的位。
但是作者为了兼容ascii,所以牺牲了一部分位。不然中文就可以2个字节表示也说不定。
指的注意的是:这种变长字符的方式还有其他的方式,例如mqtt 的消息里面的剩余字符字段就是变长的方式。
每个字节只用前7位,0表示结束,1表示还有剩余。
两种编码对比:
同样都支持ascii。
utf8的变长方式:可以知道提前知道有几个字节,起到一个校验的作用,但是会导致浪费一部分字节。
mqtt remaining字段的变长方式:无法知道有多少字节,但是会节省一部分字节。
6.utf-16
对于unicode BMP的65536个字符,采取一一映射到16位数值的方式。即采用2个字节,一个代码单元。
对于超过16位的数值,采用4个字节,即两个代码单元组成,这两个代码单元称为一个代理项对(surrogate pair)
注意U+D800和U+DFFF中间是unicode是没有定义字符,这是专门为UTF-16考虑的。
我们知道非BMP字符范围在U+10000~U+10FFFF,总共包含0xFFFFF个code point,即20位。
我们将前10位作为代理项的高位代理,我们将前10位+0XD800可以得到范围是 0XD800~0XDBFF
我们将后10位作为代理项的低位代理,我们将后10位+0XDC00可以得到范围是 0XDC00~0XDFFF
可通过代码看出:
这样的好处在于,可以分清楚一个代码单元(16位),属于BMP还是高代理项还是低代理项。三者的数字范围互不重叠。
UTF16和UTF8都有”自我同步”的特点,即通过一个代码点,就能推导出完整的代码序列,可以知道哪个字节开始,那个字节结束。