Unicode 與 UTF-8

最近在開發(fā)上遇到了點(diǎn)編碼的問題绢掰,又重新學(xué)習(xí)了字符集以及編碼的知識(shí)没酣。特此記錄一下舀患。

核心

我比較喜歡一開始講述核心的東西蚓峦,這樣子讀者可以帶著這些知識(shí)往下看舌剂,并且在翻閱到這個(gè)頁(yè)面的時(shí)候可以一眼就可以看到最關(guān)鍵的內(nèi)容。

  • Unicode是字符集
  • UTF-8是編碼規(guī)則

Unicode

在很久很久之前暑椰,幾個(gè)美國(guó)人發(fā)現(xiàn)用8個(gè)可以開合的晶體管來表示不同的狀態(tài)霍转,即可以表示2^8=256種狀態(tài),并且他們把這個(gè)8個(gè)開關(guān)稱為一個(gè)字節(jié)一汽。然后這幾個(gè)人美國(guó)人又規(guī)定避消,把編碼(十進(jìn)制值)從0到32的值所表示的狀態(tài)分別規(guī)定了特殊的用途,終端召夹、打印機(jī)等輸出設(shè)備一收到這些值岩喷,就會(huì)做出響應(yīng)的操作。
比如:
輸出設(shè)備遇到0x10监憎,終端就換行均驶。
輸出設(shè)備遇到0x07,終端就發(fā)出嘟嘟的聲響枫虏。(很多人可能不知道命令行其實(shí)是可以發(fā)出警報(bào)聲的)
輸出設(shè)備遇到0x1b妇穴,打印機(jī)就打印反白的字符,或者終端用彩色表示字母隶债。腾它、
輸出設(shè)備遇到...
好了,總之這就是這個(gè)幾個(gè)美國(guó)人設(shè)計(jì)的規(guī)范死讹。這幾個(gè)美國(guó)人感覺這樣子做很不錯(cuò)瞒滴,并且把0x20以下的字節(jié)碼狀態(tài)稱為控制碼。此時(shí)這幾個(gè)美國(guó)人又把所有的空格赞警、標(biāo)點(diǎn)符號(hào)妓忍、數(shù)字、大小寫字母分別用連續(xù)的字節(jié)狀態(tài)來表示愧旦,一直定義到了127世剖。這樣子當(dāng)著幾個(gè)人每個(gè)人想要輸出字符串到輸出設(shè)備時(shí)候,只要輸入對(duì)應(yīng)的二進(jìn)制的狀態(tài)碼即可笤虫。其實(shí)這也是最早的計(jì)算機(jī)的原型旁瘫。很快,這幾個(gè)美國(guó)人把這個(gè)編碼向全國(guó)推廣琼蚯,希望可以統(tǒng)一字符的標(biāo)準(zhǔn)酬凳。果不其然,這種字符集標(biāo)準(zhǔn)很快在美國(guó)地區(qū)得到普及遭庶,并且有了一個(gè)新的名稱--ASCII(American Standard Code for Information Interchange宁仔,美國(guó)信息互換標(biāo)準(zhǔn)代碼)編碼。

后來峦睡,隨著計(jì)算機(jī)的普及翎苫。世界各地的人都開始用計(jì)算機(jī)。就以我們國(guó)家做例子赐俗。但是這個(gè)字符集的短板也就出現(xiàn)了拉队,當(dāng)時(shí)中國(guó)人發(fā)現(xiàn)計(jì)算機(jī)無(wú)法輸入中文!原因就在于那幾個(gè)美國(guó)人只定義了英文的英語(yǔ)字符(a,b,c,d...等)阻逮。根本沒有考慮其他國(guó)家的語(yǔ)言輸入粱快。
于是我們勤勞的中國(guó)人打算自己定義一套適用于中文的字符集。我們?cè)?code>ASCII字符集的基礎(chǔ)上叔扼,把127號(hào)的以后的編碼都直接去掉了事哭,規(guī)定:一個(gè)小于127的字符的與原來的意義相同,但是當(dāng)兩個(gè)大于127的字符連在一起瓜富,就表示一個(gè)漢字鳍咱,前面的一個(gè)字節(jié)(稱為高字節(jié))從0xA1用到0xF7,后面一個(gè)字節(jié)(低字節(jié))從0xA1到0xFE与柑,這樣子我們就能夠組合處于大于7000多個(gè)漢子了谤辜。在這些編碼里蓄坏,我們還把數(shù)學(xué)符號(hào)、羅馬希臘的字母丑念、日文的假名們都編進(jìn)去了涡戳,連在 ASCII 里本來就有的數(shù)字、標(biāo)點(diǎn)脯倚、字母都統(tǒng)統(tǒng)重新編了兩個(gè)字節(jié)長(zhǎng)的編碼渔彰,這就是常說的”全角”字符,而原來在127號(hào)以下的那些就叫”半角”字符了推正。中國(guó)人民看到這樣很不錯(cuò)恍涂,于是就把這種漢字方案叫做 “GB2312“。GB2312 是對(duì) ASCII 的中文擴(kuò)展植榕。
欲望推動(dòng)著科技不斷進(jìn)步再沧。后來隨著各種字符文字的增加,又在GB2312的基礎(chǔ)上又?jǐn)U展出了GBK編碼方案内贮、GBK又?jǐn)U展出了GB18030編碼方案产园。
可以看到,ASCII是一個(gè)字節(jié)表示一個(gè)字符夜郁,而為了支持中文漢字的編碼方案什燕,我們出現(xiàn)了兩個(gè)字符表示一個(gè)漢字。但是在計(jì)算機(jī)如何識(shí)別它們呢竞端?答案是計(jì)算機(jī)是按照ASCII的標(biāo)準(zhǔn)進(jìn)行讀取的屎即,所以在當(dāng)時(shí)的編碼方案下,一個(gè)中文是算兩個(gè)英文字符的事富。

在偉大的中國(guó)智慧人民在創(chuàng)新的同時(shí)技俐,在地球上其他國(guó)家其他地區(qū)的人也在創(chuàng)建適用于它們文字的編碼方案。
于是問題就出來了统台。兩個(gè)編碼方案不一樣的計(jì)算機(jī)無(wú)法實(shí)現(xiàn)正常的交流雕擂。

為了解決這個(gè)問題。一個(gè)叫做ISO(國(guó)際標(biāo)準(zhǔn)化組織)的組織出現(xiàn)了贱勃,它們想解決這個(gè)問題井赌。他們采用的解決方案也很簡(jiǎn)單:廢除了所有的地區(qū)性的編碼方案,自己重新搞了一個(gè)包括了地球上所有文字贵扰、所有字符和符號(hào)的編碼仇穗。然后推廣并讓大家都使用它。這就是Unicode戚绕。

Unicode規(guī)定:全部字符都必須用兩個(gè)以及兩個(gè)以上字節(jié)來定義纹坐,也就是必須16位以及16位以上來統(tǒng)一所有的字符,對(duì)于ASCII里的127號(hào)以及以下的字符編碼保持不變舞丛,只是將其長(zhǎng)度從8位擴(kuò)展至16位耘子,高位補(bǔ)0果漾。這樣做的問題也很明顯,就是當(dāng)文本中的所有的字符都是英文時(shí)谷誓,會(huì)浪費(fèi)一倍的儲(chǔ)存空間跨晴。在Unicode中,無(wú)論這個(gè)文字是由多少個(gè)字節(jié)組成的片林,都是算位一個(gè)字符。

Unicode存在以下幾個(gè)缺點(diǎn)

  • 當(dāng)讀取一個(gè)文本文件時(shí)候的怀骤,計(jì)算機(jī)會(huì)無(wú)法正常讀取文本內(nèi)容费封。
    因?yàn)樵趗nicode中的字節(jié)都是可變的,從2個(gè)字節(jié)到N個(gè)字節(jié)不等蒋伦,當(dāng)某個(gè)文本中包含同時(shí)包含有兩個(gè)和三個(gè)字節(jié)的字符時(shí)候弓摘,計(jì)算機(jī)很有可能將三個(gè)字節(jié)的文本拆開來讀取。我這里有一段內(nèi)容為你好簡(jiǎn)書痕届,假設(shè)這四個(gè)字在Unicode占用的字節(jié)數(shù)分別為:2個(gè)字節(jié)韧献、3個(gè)字節(jié)、3個(gè)字節(jié)研叫。2個(gè)字節(jié)锤窑。那么計(jì)算機(jī)在讀取這段文字的時(shí)候,就很容易讀成22222字節(jié)的方式來讀出五個(gè)字符嚷炉,當(dāng)然渊啰,讀取出來的內(nèi)容和原來的你好簡(jiǎn)書是完全不一樣的。
  • 當(dāng)文本文字中有英文字符的時(shí)申屹,必然會(huì)造成存儲(chǔ)空間的浪費(fèi)绘证。
    就像上面我們所說的,unicode中所有的字符都至少為兩個(gè)字節(jié)哗讥,這就出現(xiàn)了問題嚷那。一個(gè)ASCII的英文字只需要占用一個(gè)字節(jié)就可表示,但是在unicode中要用兩個(gè)字節(jié)杆煞。所以當(dāng)文本字符內(nèi)容中英文字符比較多的情況下魏宽,存儲(chǔ)空間、以及網(wǎng)絡(luò)傳輸帶寬(文件傳輸?shù)臅r(shí)候)浪費(fèi)就特別明顯索绪。

由于這些原因湖员,Unicode在很長(zhǎng)的一段時(shí)間內(nèi)無(wú)法推廣,直到互聯(lián)網(wǎng)的出現(xiàn)瑞驱,為了解決Unicode如何在網(wǎng)絡(luò)傻姑娘傳輸?shù)膯栴}娘摔,各種各類的UTF(UCS Transfer Format)的標(biāo)準(zhǔn)誕生了。

UTF

UTF是個(gè)統(tǒng)稱唤反,它包括了UTF-8凳寺、UTF-16等傳輸標(biāo)準(zhǔn)鸭津。不同的地方在于,UTF-8每次傳輸8個(gè)位的數(shù)據(jù)肠缨,而后者每次傳輸?shù)臄?shù)據(jù)大小為16位逆趋。
UTF-8目前是互聯(lián)上使用最廣的一種unicode的實(shí)現(xiàn)方式,這是為傳輸而設(shè)計(jì)的編碼晒奕,并使編碼無(wú)國(guó)家闻书。UTF-8最大的一個(gè)特點(diǎn),就是它是一種變長(zhǎng)的編碼方式脑慧。它可以使用1~4個(gè)字節(jié)來表示一個(gè)字符魄眉,根據(jù)不同的符號(hào)而變化所要存儲(chǔ)的字節(jié)長(zhǎng)度。當(dāng)字符在ASCII碼的范圍內(nèi)闷袒,就用一個(gè)字節(jié)來表示坑律,當(dāng)unicode中一個(gè)漢字表示兩個(gè)字節(jié)時(shí),在UTF-8中用三個(gè)字節(jié)來表示囊骤。
那怎么將unicode轉(zhuǎn)換為utf-8編碼呢晃择?


Unicode符號(hào)范圍        | UTF-8編碼方式
(十六進(jìn)制)             | (二進(jìn)制)
----------------------+---------------------------------------------
      0 <--> 0x7f     | 0xxxxxxx
   0x80 <--> 0x7FF    | 110xxxxx 10xxxxxx
  0x800 <--> 0xFFFF   | 1110xxxx 10xxxxxx 10xxxxxx
0x10000 <--> 0x10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
                       ····
                       ····

這就是unicode轉(zhuǎn)為utf-8的算法規(guī)則。這算法規(guī)則也很好理解也物,以第一行算法為例子宫屠,二進(jìn)制最大的值為01111111,換算成十六進(jìn)制就是0x7f焦除。第二行激况、第三行..都以此類推。

這里來舉幾個(gè)例子膘魄。
簡(jiǎn)字的unicode編碼為\u7b80,換算成二進(jìn)制為0111 1011 1000 0000乌逐。從算法規(guī)則中我們可以看到,簡(jiǎn)字在utf-8編碼中创葡,需要三個(gè)字節(jié)表示(0x7b80在0x800與0xFFFF之間)浙踢。然后將簡(jiǎn)字的二進(jìn)制值從低位區(qū)向高位區(qū)填充,高位沒值補(bǔ)0灿渴。那么簡(jiǎn)字在utf-8編碼中的表示為11100111 10101110 10000000洛波,即0xe7ae80

字的unicode編碼為\u4e66,換算成二進(jìn)制為100 1110 0110 0110骚露。從算法規(guī)則中我們可以得知蹬挤,書字需要三個(gè)字節(jié)來表示,得到結(jié)果為11100100 10111001 10100110,即0xe4b9a6棘幸。

A 字的unicode的編碼為\u0041焰扳,換算成二進(jìn)制為0100 0001。在utf-8中,得到的結(jié)果為0100 0001吨悍。

UTF-8編碼標(biāo)準(zhǔn)很好地解決了我們上面所說的unicode的所面臨的問題扫茅。

utf-8解決了計(jì)算機(jī)無(wú)法正確讀取unicode編碼的問題

如果讀者仔細(xì)觀察utf-8的轉(zhuǎn)換規(guī)則你會(huì)發(fā)現(xiàn)一個(gè)規(guī)律,utf-8編碼的內(nèi)容首個(gè)字節(jié)都是以0育瓜、110葫隙、1110、11110打頭躏仇,后面接上幾個(gè)10開頭的字節(jié)(單字節(jié)時(shí)候不接)恋脚。
這里以讀取某段內(nèi)容為例,計(jì)算機(jī)是這么讀取每個(gè)字符的:
當(dāng)讀取到某個(gè)字節(jié)以0開頭焰手,那么計(jì)算機(jī)就知道這是個(gè)單字節(jié)字符慧起,那么只會(huì)讀取一個(gè)字節(jié)。
當(dāng)讀取到某個(gè)字節(jié)以110開頭的册倒,那么計(jì)算機(jī)除了讀取這個(gè)110開頭的字節(jié)外,還會(huì)讀取緊跟的后面的一個(gè)字節(jié)磺送。
當(dāng)讀取到某個(gè)字節(jié)以1110開頭的驻子,那么計(jì)算機(jī)除了讀取這個(gè)1110開頭的字節(jié)外,還會(huì)讀取緊跟后面的兩個(gè)字節(jié)估灿。
當(dāng)讀取到某個(gè)字節(jié)以11110開頭的崇呵,那么計(jì)算機(jī)除了讀取這個(gè)11110開頭的字節(jié),還會(huì)讀取緊跟后面的三個(gè)字節(jié)馅袁。
....
將該字符所需要的字節(jié)讀取出來后域慷,轉(zhuǎn)換為unicode值(注意這里和上面的轉(zhuǎn)換方式是相反的),最后從unicode值的映射中獲取到這個(gè)值所對(duì)應(yīng)的字符汗销,最后將這個(gè)字符在屏幕上顯示出來犹褒。
在這種編碼下,計(jì)算機(jī)能正確讀取每個(gè)字符的字節(jié)個(gè)數(shù)弛针。從而獲取獲取到正確的字符叠骑。

utf-8解決了存儲(chǔ)空間和網(wǎng)絡(luò)帶寬資源浪費(fèi)的問題

無(wú)論是存儲(chǔ)空間和網(wǎng)絡(luò)帶寬的資源浪費(fèi),都是因?yàn)樵趗nicode中削茁,為英文字符定義了多余的字節(jié)空間造成的宙枷。而utf-8很巧妙地解決了這一問題。從utf-8編碼的轉(zhuǎn)換規(guī)則中我們可以看到茧跋,一個(gè)英文字符在unicode中占用兩個(gè)字節(jié)慰丛,而在utf-8中只占用了一個(gè)字節(jié)。但是其實(shí)瘾杭!在utf-8中漢字的字節(jié)數(shù)反而增加了诅病,比如我們上文說的簡(jiǎn)字,在unicode中占用了兩個(gè)字節(jié),而在utf-8中要用三個(gè)字節(jié)來表示睬隶。不過這并不是資源的浪費(fèi)锣夹,而是utf-8編碼方案為了解決上面所說的那個(gè)問題而規(guī)定的標(biāo)準(zhǔn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末苏潜,一起剝皮案震驚了整個(gè)濱河市银萍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌恤左,老刑警劉巖贴唇,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異飞袋,居然都是意外死亡戳气,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門巧鸭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓶您,“玉大人,你說我怎么就攤上這事纲仍⊙礁ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵郑叠,是天一觀的道長(zhǎng)夜赵。 經(jīng)常有香客問我,道長(zhǎng)乡革,這世上最難降的妖魔是什么寇僧? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮沸版,結(jié)果婚禮上嘁傀,老公的妹妹穿的比我還像新娘。我一直安慰自己视粮,他們只是感情好心包,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著馒铃,像睡著了一般蟹腾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上区宇,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天娃殖,我揣著相機(jī)與錄音,去河邊找鬼议谷。 笑死炉爆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芬首,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼赴捞,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了郁稍?” 一聲冷哼從身側(cè)響起赦政,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎耀怜,沒想到半個(gè)月后恢着,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡财破,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年掰派,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片左痢。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡靡羡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俊性,到底是詐尸還是另有隱情亿眠,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布磅废,位于F島的核電站,受9級(jí)特大地震影響荆烈,放射性物質(zhì)發(fā)生泄漏拯勉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一憔购、第九天 我趴在偏房一處隱蔽的房頂上張望宫峦。 院中可真熱鬧,春花似錦玫鸟、人聲如沸导绷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妥曲。三九已至,卻和暖如春钦购,著一層夾襖步出監(jiān)牢的瞬間檐盟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工押桃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留葵萎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像羡忘,于是被迫代替她去往敵國(guó)和親谎痢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容