計(jì)算機(jī)只能處理二進(jìn)制的數(shù)據(jù)什燕,其它形式的數(shù)據(jù)都只能轉(zhuǎn)換為二進(jìn)制后才能被cpu處理及存儲(chǔ)载迄。轉(zhuǎn)換就涉及到要有一套字符編碼岛啸,即字符與二進(jìn)制的對(duì)應(yīng)關(guān)系徘钥。
1. ASCII 編碼
全稱American Standard Code for Information Interchange 美國信息交換標(biāo)準(zhǔn)代碼,上個(gè)世紀(jì)60年代离赫,美國制定的一套字符編碼芭逝,對(duì)英語字符與二進(jìn)制位之間的關(guān)系,做了統(tǒng)一規(guī)定渊胸。ASCII用1個(gè)字節(jié)(8位二進(jìn)制)來表示一個(gè)字符旬盯,因此八個(gè)二進(jìn)制位就可以組合出256種狀態(tài)(從0000000到11111111),但ASCII碼一共規(guī)定了128個(gè)字符的編碼翎猛,只占用了一個(gè)字節(jié)的后面7位胖翰,最前面的1位統(tǒng)一規(guī)定為0。比如:字母a切厘,用二進(jìn)制表示01100001(十進(jìn)制值為97)萨咳。
英語128個(gè)符號(hào)編碼已足夠,但是顯示不同國家的語言時(shí)疫稿,128個(gè)符號(hào)是不夠的培他。于是有的國家開始利用ASCII編碼里的高位,0—127表示的符號(hào)是一樣的遗座,不同國家在128—255這一段所表示的字符卻不同舀凛。在字符比較多的國家,255個(gè)字符也是不夠的途蒋,因此仍采用1個(gè)字節(jié)的編碼受到限制猛遍。
其它國家為了顯示本國的語言,都對(duì)ASCII碼進(jìn)行了擴(kuò)展号坡,加入了本國的語言編碼螃壤,這種編碼方式為ANSI編碼,用2個(gè)字節(jié)來表示筋帖,ANSI編碼跟操作系統(tǒng)有直接關(guān)系,你安裝什么操作系統(tǒng)冤馏,那你的ANSI編碼就是相應(yīng)的編碼日麸。例如:我們安裝的是中文操作系統(tǒng),對(duì)應(yīng)的默認(rèn)編碼GB2312逮光。
- GB2312編碼:簡體中文代箭、全角字符編碼,理論上最多表示65536個(gè)漢字涕刚;
- GBK編碼:對(duì)GB2312進(jìn)行了擴(kuò)展嗡综,用于顯示罕見漢字;
- BIG5編碼:繁體漢字編碼杜漠;
- JIS編碼:日本文字編碼极景。
2. Unicode
在打開一個(gè)文本文件之前察净,需要知道它的編碼方式,否則用錯(cuò)誤的編碼方式解讀盼樟,就會(huì)出現(xiàn)亂碼氢卡。這是因?yàn)椋澜缟洗嬖谥喾N編碼方式晨缴,同一個(gè)二進(jìn)制數(shù)字可以被解釋成不同的符號(hào)译秦。
若有一種編碼,將世界上所有的符號(hào)都納入其中击碗,每一個(gè)符號(hào)都給予一個(gè)獨(dú)一無二的編碼筑悴,就可以解決亂碼問題,Unicode應(yīng)運(yùn)而生稍途。
Unicode編碼集合可以容納100多萬個(gè)符號(hào)耘沼,每個(gè)符號(hào)的編碼都不一樣良蒸。比如U+0042表示英語的大寫字母"B",U+1F600表示"??",U+8DF3表示漢字"跳"娘摔。具體的符號(hào)對(duì)應(yīng)表,可以查詢unicode.org太雨、Unicode Utilities或者專門的漢字對(duì)應(yīng)表蕊退。
Unicode編碼的符號(hào)集只規(guī)定了符號(hào)的二進(jìn)制代碼,卻沒有規(guī)定這個(gè)二進(jìn)制代碼應(yīng)該如何存儲(chǔ)猖吴。比如漢字"跳"的unicode是十六進(jìn)制數(shù)8DF3摔刁,轉(zhuǎn)換成二進(jìn)制數(shù)足足有15位(1000110111110011),也就是說這個(gè)符號(hào)的表示至少需要2個(gè)字節(jié)海蔽。也會(huì)有序號(hào)更大的符號(hào)共屈,可能需要3、4個(gè)字節(jié)党窜,甚至更多拗引。
那么,如何才能區(qū)別Unicode和ASCII幌衣?Unicode編碼怎么在計(jì)算機(jī)內(nèi)存儲(chǔ)呢矾削?若每個(gè)符號(hào)都占用四個(gè)字節(jié)編碼表示,那么每個(gè)英文字母前三個(gè)字節(jié)是0豁护,極大的浪費(fèi)存儲(chǔ)空間哼凯,原英文文本文件的大小會(huì)因此大出三倍,顯然無法接受楚里。
3. UTF-8
UTF-8是Unicode的實(shí)現(xiàn)方式之一断部,這種Unicode/UTF-8統(tǒng)一編碼方式有利于數(shù)據(jù)的傳輸和計(jì)算機(jī)科學(xué)的發(fā)展。其他實(shí)現(xiàn)方式還包括UTF-16(字符用兩個(gè)字節(jié)或四個(gè)字節(jié)編碼)和UTF-32(字符用四個(gè)字節(jié)編碼)班缎,不過在互聯(lián)網(wǎng)上基本不用蝴光。
UTF-8的編碼規(guī)則:
- 對(duì)于單字節(jié)的字符她渴,字節(jié)的第一位設(shè)為0,后面7位為這個(gè)符號(hào)的Unicode虱疏,因此對(duì)于英語字符惹骂,UTF-8和ASCII碼相同;
- 對(duì)于n字節(jié)的字符(n>1)做瞪,第一個(gè)字節(jié)的前n位都設(shè)為1对粪,第n+1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10装蓬。剩下的沒有提及的二進(jìn)制位著拭,全部為這個(gè)符號(hào)的unicode碼。
Unicode符號(hào)范圍 | UTF-8編碼方式
(十六進(jìn)制)|(二進(jìn)制)
--------------------+---------------------------------------------
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已知"跳"的Unicode是4DF3(1000110111110011)牍帚,根據(jù)其值位于的范圍可知儡遮,"跳"的UTF-8編碼是"11101000 10110111 10110011",轉(zhuǎn)換成十六進(jìn)制就是E8B7B3暗赶。
也就是說鄙币,UTF-8編碼是一種變長的編碼,它可以使用1~4個(gè)字節(jié)表示一個(gè)符號(hào)蹂随,根據(jù)不同的符號(hào)而變化字節(jié)長度十嘿。
在Mac上創(chuàng)建一個(gè)txt文檔,在偏好設(shè)置中岳锁,能夠選擇當(dāng)前文檔的存儲(chǔ)編碼方式绩衷,也可進(jìn)行編碼之間的轉(zhuǎn)換:
4. 編碼中的Little endian和Big endian
若將一個(gè)十六進(jìn)制數(shù)據(jù)"8DF3"直接進(jìn)行存儲(chǔ),需要用兩個(gè)字節(jié)存儲(chǔ)激率,一個(gè)字節(jié)是8D咳燕,另一個(gè)字節(jié)是F3。那么乒躺,計(jì)算機(jī)在存儲(chǔ)空間的地址順序上招盲,是將8D在前,還是將F3在前呢嘉冒?
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è)記事本文本文件,輸入一個(gè)漢字作為內(nèi)容纳胧,依次采用ANSI镰吆、Unicode、Unicode big endian 和 UTF-8編碼方式保存跑慕。然后万皿,可以通過"十六進(jìn)制"的形式觀察該文件的內(nèi)部編碼方式、存儲(chǔ)有何不同核行。
1)ANSI:文件的編碼就是兩個(gè)字節(jié)"D1 CF"牢硅,這正是"嚴(yán)"的GB2312編碼,這也暗示GB2312是采用大頭方式存儲(chǔ)的芝雪。
2)Unicode:編碼是四個(gè)字節(jié)"FF FE 25 4E"减余,其中"FF FE"表明是小頭方式存儲(chǔ),真正的編碼是4E25惩系。
3)Unicode big endian:編碼是四個(gè)字節(jié)"FE FF 4E 25"位岔,其中"FE FF"表明是大頭方式存儲(chǔ)。
4)UTF-8:編碼是六個(gè)字節(jié)"EF BB BF E4 B8 A5"抒抬,前三個(gè)字節(jié)"EF BB BF"表示這是UTF-8編碼,后三個(gè)"E4B8A5"就是"嚴(yán)"的具體編碼悴侵,它的存儲(chǔ)順序與編碼順序是一致的。
5. 總結(jié)
在計(jì)算機(jī)內(nèi)存中統(tǒng)一使用Unicode編碼可免,當(dāng)需要保存到硬盤或者需要傳輸?shù)臅r(shí)候,就轉(zhuǎn)換為UTF-8(或其他)編碼浇借。
不同的字符集中,字符有不同的字符編碼妇垢,所以要想判斷某個(gè)輸入的數(shù)據(jù)是不是某類字符的時(shí)候巾遭,先確定當(dāng)前使用的字符集闯估,找到該字符集下該類型字符對(duì)應(yīng)的字符編碼范圍灼舍,即可判斷,如判斷GB2312下的漢字涨薪。
系統(tǒng)只是把這個(gè)字符告訴終端骑素,終端去字體中找到這個(gè)字符對(duì)應(yīng)的圖像,再把這個(gè)圖像顯示出來刚夺。如果字體中沒有献丑,那就會(huì)顯示方框等所謂的亂碼末捣。
emoji的支持也是一樣的,所以實(shí)際上是字體的功勞创橄÷嶙觯可能系統(tǒng)在emoji的渲染上支持一些額外的特性(比如顏色,或者干脆用圖片來代表emoji字符)妥畏。
現(xiàn)代操作系統(tǒng)內(nèi)部都是用Unicode來處理字符的邦邦。設(shè)定字符集實(shí)際上是告訴系統(tǒng)如何處理外碼和內(nèi)碼的對(duì)應(yīng),比如同一個(gè)字符咖熟,在UTF-8和UTF-16中的編碼可能是不同的圃酵,字節(jié)數(shù)量也可能是不同的,但是對(duì)應(yīng)的unicode其實(shí)同一個(gè)馍管。比如系統(tǒng)處理一個(gè)字符郭赐,根據(jù)設(shè)定的字符集找到對(duì)應(yīng)的UTF-8編碼輸出給終端,但是終端卻是用UTF-16的規(guī)則來理解這些編碼确沸,那自然就會(huì)出錯(cuò)了捌锭。
參考文章,感謝:
https://www.cnblogs.com/ooon/p/4818574.html
https://www.cnblogs.com/cthon/p/9297232.html
https://blog.csdn.net/LightUpHeaven/article/details/92001322