字符編碼的奧秘

字符編碼

你是否認為“ASCII碼 = 一個字符就是8比特”暑始?你是否認為一個字節(jié)就是一個字符,一個字符就是8比特七婴?你是否還認為你是否還認為UTF-8就是用8比特表示一個字符?如果真的是這樣認為認真讀完這篇文章吧!

為什么要有編碼切蟋?

首先大家需要明確的是在計算機里所有的數(shù)據(jù)都是字節(jié)的形式存儲,處理的鸽素。我們需要這些字節(jié)來表示計算機里的信息隆判。但是這些字節(jié)本身又是沒有任何意義的,所以我們需要對這些字節(jié)賦予實際的意義俯渤。所以才會制定各種編碼標準呆细。

編碼模型

首先需要明確的是存在兩種編碼模型

簡單字符集

在這種編碼模型里,一個字符集定義了這個字符集里包含什么字符八匠,同時把每個字符如何對應成計算機里的比特也進行了定義絮爷。例如ASCII,在ASCII里直接定義了A -> 0100 0001梨树。

現(xiàn)代編碼模型

在現(xiàn)代編碼模型里要知道一個字符如何映射成計算機里比特坑夯,需要經(jīng)過如下幾個步驟。

  1. 知道一個系統(tǒng)需要支持哪些字符抡四,這些字符的集合被稱為字符表(Character repertoire)
  2. 給字符表里的抽象字符編上一個數(shù)字柜蜈,也就是字符集合到一個整數(shù)集合的映射。這種映射稱為編碼字符集(CCS:Coded Character Set),unicode是屬于這一層的概念指巡,跟計算機里的什么進制啊沒有任何關(guān)系淑履,它是完全數(shù)學的抽象的。
  3. 將CCS里字符對應的整數(shù)轉(zhuǎn)換成有限長度的比特值藻雪,便于以后計算機使用一定長度的二進制形式表示該整數(shù)秘噪。這個對應關(guān)系被稱為字符編碼表(CEF:Character Encoding Form)UTF-8, UTF-16都屬于這層。
  4. 對于CEF得到的比特值具體如何在計算機中進行存儲阔涉,傳輸缆娃。因為存在大端小端的問題捷绒,這就會跟具體的操作系統(tǒng)相關(guān)了。這種解決方案稱為字符編碼方案(CES:Character Encoding Scheme)贯要。

平常我們所說的編碼都在第三步的時候完成了,都沒有涉及到CES暖侨。所以CES并不在本文的討論范圍之內(nèi)。
現(xiàn)在也許有人會想為什么要有現(xiàn)代的編碼模型崇渗?為什么在現(xiàn)在的編碼模型要拆分出這么多概念字逗?直接像原始的編碼模型直接都規(guī)定好所有的信息不行嗎?這些問題在下文的編碼發(fā)展史中都會有所闡述宅广。

編碼的發(fā)展史

ASCII

ASCII出現(xiàn)在上個世紀60年代的美國葫掉,ASCII一共定義了128個字符,使用了一個字節(jié)的7位跟狱。定義的這些字符包括英文字母A-Z俭厚,a-z,數(shù)字0-9驶臊,一些標點符號和控制>符號挪挤。在Shell里輸入man ASCII,可以看到完整的ASCII字符集关翎。ASCII采用的編碼模型是簡單字符集扛门,它直接定義了一個字符的比特值表示。里例如上文提到的A -> 0100 0001纵寝。也就是ASCII直接完成了現(xiàn)代編碼模型的前三步工作论寨。
在英語系國家里ASCII標準很完美。但是不要忘了世界上可有好幾千種語言爽茴,這些語言里不僅只有這些符號啊葬凳。如果使用這些語言的人也想使用計算機,ASCII就遠遠不夠了闹啦。到這里編碼進入了混亂的時代沮明。

混亂時代

人們知道計算機的一個字節(jié)是8位,可以表示256個字符窍奋。ASCII卻只使用了7位荐健,所以人們決定把剩余的一位也利用起來。這時問題出現(xiàn)了琳袄,人們對于已經(jīng)規(guī)定好的128個字符是沒有異議的江场,但是不同語系的人對于其他字符的需求是不一樣的,所以對于剩下的128個字符的擴展會千奇百怪窖逗。而且更加混亂的是址否,在亞洲的語言系統(tǒng)中有更多的字符,一個字節(jié)無論如何也滿足不了需求了。例如僅漢字就有10萬多個佑附,一個字節(jié)的256表示方式怎么能夠滿足呢樊诺。于是就又產(chǎn)生了各種多字節(jié)的表示一個字符方法(gbk就是其中一種),這就使整個局面更加的混亂不堪音同。(希望看到這里的你不再認為一個字節(jié)就是一個字符词爬,一個字符就是8比特)。每個語系都有自己特定的編碼頁(code pages)的狀況权均,使得不同的語言出現(xiàn)在同一臺計算機上顿膨,不同語系的人在網(wǎng)絡(luò)上進行交流都成了癡人說夢。這時Unicode出現(xiàn)了叽赊。

Unicode

Unicode就是給計算機中所有的字符各自分配一個代號恋沃。Unicode通俗來說是什么呢?就是現(xiàn)在實現(xiàn)共產(chǎn)主義了必指,各國人民不在需要自己特定的國家身份證囊咏,而是給每人一張全世界通用的身份證。Unicode是屬于編碼字符集(CCS)的范圍塔橡。Unicode所做的事情就是將我們需要表示的字符表中的每個字符映射成一個數(shù)字匆笤,這個數(shù)字被稱為相應字符的碼點(code point)。例如“嚴”字在Unicode中對應的碼點是U+0x4E25谱邪。

到目前為止,我們只是找到了一堆字符和數(shù)字之間的映射關(guān)系而已庶诡,只到了CCS的層次惦银。這些數(shù)字如何在計算機和網(wǎng)絡(luò)中存儲和展示還沒有提到。

字符編碼

前面還都屬于字符集的概念末誓,現(xiàn)在終于到CEF的層次了扯俱。為了便于計算的存儲和處理,現(xiàn)在我們要把哪些純數(shù)學數(shù)字對應成有限長度的比特值了喇澡。最直觀的設(shè)計當然是一個字符的碼點是什么數(shù)字迅栅,我們就把這個數(shù)字轉(zhuǎn)換成相應的二進制表示,如“嚴”在Unicode中對應的數(shù)字是0x4E25,他的二進制是100 1110 0010 0101晴玖,也就是嚴這個字需要兩個字節(jié)進行存儲读存。按照這種方法大部分漢字都可以用兩個字節(jié)來表示了。但是還有其他語系的存在呕屎,沒準兒他們所使用的字符用這種方法轉(zhuǎn)換就需要4個字節(jié)让簿。這樣問題又來了到底該使用幾個字節(jié)表示一個字符呢?如果規(guī)定兩個字節(jié)秀睛,有的字符會表示不出來尔当,如果規(guī)定較多的字節(jié)表示一個字符,很多人又不答應蹂安,因為本來有些語言的字符兩個字節(jié)處理就可以了椭迎,憑什么用更多的字節(jié)表示锐帜,多么浪費。

這時就會想可不可以用變長的字節(jié)來存儲一個字符呢畜号?如果使用了變長的字節(jié)表示一個字符缴阎,那就必須要知道是幾個字節(jié)表示了一個字符,要不然計算機可沒那么聰
明弄兜。下面介紹一下最常用的UTF-8(UTF是Unicode Transformation Format的縮寫)的設(shè)計药蜻。請看下圖(來自阮一峰的博客)

x表示可用的位

通過UTF-8的對應關(guān)系可以把每個字符在Unicode中對應的碼點,轉(zhuǎn)換成相應的計算機的二進制表示替饿∮镌螅可以發(fā)現(xiàn)按照UTF-8進行轉(zhuǎn)換是完全兼容原先的ASCII的;而且在多字節(jié)表示一個字符時视卢,開頭有幾個1就表示這個字符按照UTF-8轉(zhuǎn)換后由幾個字節(jié)表示踱卵。下面一個實例子來自阮一峰的博客

已知“嚴”的unicode是4E25(100111000100101),根據(jù)上表据过,可以發(fā)現(xiàn)4E25處在第三行的范圍內(nèi)(0000 0800-0000 FFFF)惋砂,因此“嚴”的UTF-8編碼需要三個字節(jié),
即格式是“1110xxxx 10xxxxxx 10xxxxxx”绳锅。然后西饵,從“嚴”的最后一個二進制位開始,依次從后向前填入格式中的x鳞芙,多出的位補0眷柔。這樣就得到了,“嚴”的UTF-8編碼>是“11100100 10111000 10100101”原朝,轉(zhuǎn)換成十六進制就是0xE4B8A5驯嘱。

除了UTF-8這種轉(zhuǎn)換方法,還存在UTF-16喳坠,UTF-32等等轉(zhuǎn)換方法鞠评。這里就不再多做介紹.(注意UTF后邊的數(shù)字代表的是碼元的大小。碼元(Code Unit)是指一個已編碼的文本中具有最短的比特組合的單元壕鹉。對于UTF-8來說剃幌,碼元是8比特長;對于UTF-16來說晾浴,碼元是16比特長锥忿。換一種說法就是UTF-8的是以一個字節(jié)為最小單位的,UTF-16是以兩個字節(jié)為最小單位的怠肋。)

結(jié)束語

花了兩天時間終于寫完了敬鬓,相信看到這里大家對于字符編碼有了較為清楚的認識,當然文章中肯定存在不準確之處,希望大家批評指正钉答。
郵箱:acmerfight圈gmail.com

參考資料

字符編碼
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
字符編碼筆記:ASCII础芍,Unicode和UTF-8
字符集和字符編碼
Windows 記事本的 ANSI、Unicode数尿、UTF-8 這三種編碼模式有什么區(qū)別仑性?
如何向非技術(shù)人員解釋 Unicode 是什么
字符編解碼的故事(ASCII,ANSI右蹦,Unicode诊杆,Utf-8)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市何陆,隨后出現(xiàn)的幾起案子晨汹,更是在濱河造成了極大的恐慌,老刑警劉巖贷盲,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淘这,死亡現(xiàn)場離奇詭異,居然都是意外死亡巩剖,警方通過查閱死者的電腦和手機铝穷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來佳魔,“玉大人曙聂,你說我怎么就攤上這事【舷剩” “怎么了筹陵?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長镊尺。 經(jīng)常有香客問我,道長并思,這世上最難降的妖魔是什么庐氮? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮宋彼,結(jié)果婚禮上弄砍,老公的妹妹穿的比我還像新娘。我一直安慰自己输涕,他們只是感情好音婶,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著莱坎,像睡著了一般衣式。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天碴卧,我揣著相機與錄音弱卡,去河邊找鬼。 笑死住册,一個胖子當著我的面吹牛婶博,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荧飞,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凡人,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了叹阔?” 一聲冷哼從身側(cè)響起挠轴,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎条获,沒想到半個月后忠荞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡帅掘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年委煤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片修档。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡碧绞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吱窝,到底是詐尸還是另有隱情讥邻,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布院峡,位于F島的核電站兴使,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏照激。R本人自食惡果不足惜发魄,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望俩垃。 院中可真熱鬧励幼,春花似錦、人聲如沸口柳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跃闹。三九已至嵌削,卻和暖如春毛好,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掷贾。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工睛榄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人想帅。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓场靴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親港准。 傳聞我的和親對象是個殘疾皇子旨剥,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

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