轉(zhuǎn)載需注明原地址,謝謝
目標(biāo):徹底弄懂字符集习蓬、編碼字符集、字符編碼集富纸、unicode集畅、utf8、utf16
1.什么叫字符集届谈。
答:比如中文就可以叫漢子字符集扰柠,英文也可以叫英文字符集,總之就是指的一套字符的集合疼约。
2.什么叫編碼字符集
答:比如 我們規(guī)定 0 代表 我卤档,1代表你,等等程剥。 我們對(duì)字符集進(jìn)行編碼劝枣,一個(gè)字符對(duì)應(yīng)一個(gè)整數(shù)序號(hào)(code point),這樣集合就叫編碼字符集织鲸。
其中較為出名的有:unicode舔腾、ascii。
3.什么叫字符編碼集
首先講講為什么字符編碼集的來(lái)歷搂擦。
有了編碼字符集后稳诚,下一步就是把字符的 code point 映射到計(jì)算機(jī)中。
常見(jiàn)的如ascii編碼集瀑踢,字符編碼集中的數(shù)字與編碼字符集中的數(shù)字字符一一對(duì)應(yīng)扳还。
然而ascii只有127個(gè)code point,當(dāng)然可以完美表示橱夭。
而unicode有理論上有U+10FFFFcode point氨距,
如果采取一一對(duì)應(yīng)的方式,那么ascii表示需要1個(gè)字節(jié)的字符到unicode上需要3個(gè)字節(jié)棘劣。
而實(shí)際開(kāi)發(fā)中俏让,ascii的使用頻率遠(yuǎn)遠(yuǎn)高于其他unicode字符,為了兼容其他字符,就讓內(nèi)存擴(kuò)大3倍首昔,所以這種一一對(duì)應(yīng)的方式是不可取的寡喝。
那么如何選擇一個(gè)合適的編碼方案呢?
- 1.首先字符編碼集應(yīng)該是變長(zhǎng)的勒奇,且越是高頻的字符越是含的字節(jié)少拘荡,這樣可以最大程度上優(yōu)化使用內(nèi)存。
- 2.其次撬陵,最好能夠兼容一部分字符集珊皿。
綜上考慮:
誕生了UTF系列和UCS系列編碼
其中UTF分為UTF-8,UTF-16,UTF-32分別代表著用8位,16位巨税,32位來(lái)代表某個(gè)單個(gè)code point蟋定。
其中UTF8和UTF16最為常用。
4.unicode
1.萬(wàn)國(guó)碼草添。與ascii兼容
2.分成17區(qū)域驶兜,每個(gè)區(qū)域我們稱為一個(gè)平面,其中每一個(gè)平面包含65536(0xFFFF)個(gè)code point远寸,第一個(gè)平面 0U+FFFF抄淑,第二個(gè)平面U+10000U+1FFFF,以此類推驰后。前兩位是編號(hào)肆资,范圍在0x0~0x10之間,后4位為代碼點(diǎn)灶芝。
3.最常見(jiàn)的是第一個(gè)平面郑原,這個(gè)平面被稱為 多語(yǔ)言平面(BMP)
4.unicode分成utf和ucs系列編碼。
5.如何判斷大小端夜涕?
什么叫大小端犯犁? 大端含義,從左往右讀(常見(jiàn))女器,小端酸役,從右往左讀。http://www.ruanyifeng.com/blog/2016/11/byte-order.html
unicode規(guī)定:
那么很自然的驾胆,就會(huì)出現(xiàn)一個(gè)問(wèn)題:計(jì)算機(jī)怎么知道某一個(gè)文件到底采用哪一種方式編碼涣澡?
Unicode 規(guī)范定義,每一個(gè)文件的最前面分別加入一個(gè)表示編碼順序的字符俏拱,這個(gè)字符的名字叫做"零寬度非換行空格"(zero width no-break space)暑塑,用FEFF表示。這正好是兩個(gè)字節(jié)锅必,而且FF比FE大1。
如果一個(gè)文本文件的頭兩個(gè)字節(jié)是FE FF,就表示該文件采用大頭方式搞隐;如果頭兩個(gè)字節(jié)是FF FE驹愚,就表示該文件采用小頭方式。
注意:這個(gè)規(guī)定是針對(duì)文件而言劣纲。實(shí)時(shí)上對(duì)于字節(jié)流而言逢捺,這沒(méi)什么意義。
5.utf-8
1.變長(zhǎng)癞季,兼容ascii
首位0:表示1字節(jié)
首位110:表示2字節(jié)
首位1110:表示3字節(jié)
首位11110:表示4字節(jié)
….
10表示當(dāng)前字節(jié)不是首位劫瞳,為中間字節(jié)。
這里有個(gè)細(xì)節(jié)绷柒,為什么要中間字節(jié)為10而不是0呢志于?
如果用0表示,相同的字節(jié)可以表示更多的位废睦。
但是作者為了兼容ascii伺绽,所以犧牲了一部分位。不然中文就可以2個(gè)字節(jié)表示也說(shuō)不定嗜湃。
指的注意的是:這種變長(zhǎng)字符的方式還有其他的方式奈应,例如mqtt 的消息里面的剩余字符字段就是變長(zhǎng)的方式。
每個(gè)字節(jié)只用前7位购披,0表示結(jié)束杖挣,1表示還有剩余。
兩種編碼對(duì)比:
同樣都支持ascii刚陡。
utf8的變長(zhǎng)方式:可以知道提前知道有幾個(gè)字節(jié)程梦,起到一個(gè)校驗(yàn)的作用,但是會(huì)導(dǎo)致浪費(fèi)一部分字節(jié)橘荠。
mqtt remaining字段的變長(zhǎng)方式:無(wú)法知道有多少字節(jié)屿附,但是會(huì)節(jié)省一部分字節(jié)。
6.utf-16
對(duì)于unicode BMP的65536個(gè)字符哥童,采取一一映射到16位數(shù)值的方式挺份。即采用2個(gè)字節(jié),一個(gè)代碼單元贮懈。
對(duì)于超過(guò)16位的數(shù)值匀泊,采用4個(gè)字節(jié),即兩個(gè)代碼單元組成朵你,這兩個(gè)代碼單元稱為一個(gè)代理項(xiàng)對(duì)(surrogate pair)
注意U+D800和U+DFFF中間是unicode是沒(méi)有定義字符各聘,這是專門(mén)為UTF-16考慮的。
我們知道非BMP字符范圍在U+10000~U+10FFFF抡医,總共包含0xFFFFF個(gè)code point躲因,即20位早敬。
我們將前10位作為代理項(xiàng)的高位代理,我們將前10位+0XD800可以得到范圍是 0XD800~0XDBFF
我們將后10位作為代理項(xiàng)的低位代理大脉,我們將后10位+0XDC00可以得到范圍是 0XDC00~0XDFFF
可通過(guò)代碼看出:
這樣的好處在于搞监,可以分清楚一個(gè)代碼單元(16位),屬于BMP還是高代理項(xiàng)還是低代理項(xiàng)镰矿。三者的數(shù)字范圍互不重疊琐驴。
UTF16和UTF8都有”自我同步”的特點(diǎn),即通過(guò)一個(gè)代碼點(diǎn)秤标,就能推導(dǎo)出完整的代碼序列绝淡,可以知道哪個(gè)字節(jié)開(kāi)始,那個(gè)字節(jié)結(jié)束苍姜。