字符編碼筆記(理論篇)

記錄一下字符編碼的有關事項,這篇文章先說說字符編碼的一些歷史和原理丰介。

1.ASCII編碼與ANSI標準

1字節(jié)(1B) = 8比特(8b) = 8個二進制位
1B的信息量 0b00000000 ~ 0b11111111 = 2^8 = 256個狀態(tài)

標準ASCII編碼使用1B的后7位,而第一位默認置0,即:
0b00000000 ~ 0b01111111 = 2^7 = 128個狀態(tài)
這128個狀態(tài)位存儲了控制字符贝室、數(shù)字契讲、大小寫字母和其他符號。詳見ASCII編碼表[]

漸漸地滑频,128個狀態(tài)不再能滿足人們的需求捡偏,不同國家(語言區(qū))都想把自己語言的字符編進ASCII編碼中,于是人們紛紛自發(fā)的使用起了1B的另外128個狀態(tài)峡迷,稱為擴展ASCII編碼银伟,其使用1B的后7位,同時第一位默認置1绘搞,即:
0b10000000 ~ 0b11111111 = 2^7 = 128個狀態(tài)
由于是自發(fā)行為彤避,每個國家(語言區(qū))都對擴展ASCII編碼有自己獨特的定義,因此彼此之間的擴展ASCII編碼是不能通用的夯辖。(標準ACII編碼區(qū)仍然通用)

麻煩還不止于此琉预,部分國家(語言區(qū))的字符數(shù)量眾多(如漢字就是十萬級別的數(shù)量),顯然擴展ASCII編碼的128個狀態(tài)不能滿足蒿褂,于是有了下面的一種編碼方式(ANSI標準編碼):

  1. 保留標準ASCII編碼的128個字符不變圆米,稱為半角
  2. 其余的字符用兩個字節(jié)來表示,這樣理論上能新增256*256=65536個編碼啄栓,稱為全角
    這也是大家最早所認知的下面這句話的由來

英文(半角)占一個字節(jié)娄帖,漢字(全角)占兩個字節(jié)

全角字符中用于編碼的兩個字節(jié)被稱為高位字節(jié)低位字節(jié)
全角字符 = 高位字節(jié) + 低位字節(jié)
高位字節(jié)和低位字節(jié)都可以選擇用三種策略編碼:

  1. 標準ASCII編碼的128個狀態(tài)
  2. 擴展ASCII編碼的128個狀態(tài)
  3. 以上都用的256個狀態(tài)

不難發(fā)現(xiàn)當這兩個字節(jié)都使用標準ASCII編碼的128個狀態(tài)時,計算機是無法分辨這是兩個半角字符昙楚,還是一個全角字符的块茁。因此全角的編碼區(qū)域?qū)嶋H上只有:
256*256 - 128*128 = 49152個
針對這個5萬個左右的編碼區(qū),不同國家(語言區(qū))制定了不同的編碼標準桂肌,我們熟悉的有:

  • GB2312数焊,大陸1980年標準(其中一級漢字3755個,二級漢字3008個崎场,包括拉丁字母佩耳、希臘字母、日文平假名及片假名字母谭跨、俄語西里爾字母在內(nèi)的全角字符682個干厚。)
  • GBK,大陸1995年標準(GB2312的擴展螃宙,增加不常用漢字與字符蛮瞄,總編碼量擴展到23940)
  • BIG-5,臺灣標準

2. Unicode編碼

隨著互聯(lián)網(wǎng)的發(fā)展谆扎,信息交流變得越來越頻繁挂捅,這就促使一種“大一統(tǒng)”的編碼方式出現(xiàn)。這種編碼可以將世界上所有的字符都編入其中堂湖,且每個狀態(tài)位和字符都唯一對應闲先。正如它的名字代表的意思那樣状土,Unicode編碼做到了。
Unicode將編碼存儲這兩個邏輯過程獨立開來伺糠。

  • 世界上的每一個字符都有且只有一個Unicode編碼方案即:字符S->Unicode(S)
  • 每一個Unicode碼都可以通過的多種方案來存儲蒙谓,這些方案的名稱即是我們常聽到的UTF-8、UTF-16训桶、UTF-32等等累驮。

2.1 編碼邏輯

下面先說一下Unicode的編碼方式:
Unicode碼的編碼范圍:0x000000 ~ 0x10FFFF
它的后四位稱為一個plane:0x0000 ~ 0xFFFF = 2^16 = 65536個狀態(tài)
前兩位代表plane的編號,一共有:0x00 ~ 0x10 = 17個plane
所以Unicode編碼一共有:17 * 65536 = 1114112個狀態(tài)
這足以將世界上所有的字符都編碼進去舵揭,而且還有很大的富余谤专。同時別忘了,預留的空白plane可遠遠多于17個(16*16=256個)
事實上琉朽,在Unicode 5.0版本中只用到了0,1稚铣,2箱叁,14,15惕医,16這幾個編號plane中的238605個狀態(tài)

2.2 存儲邏輯

Unicode編碼總算是將全世界的字符都“裝”下了耕漱,當然為了達到此目的,經(jīng)過Unicode編碼后的字符所占空間變的很大抬伺。本來只占一個字節(jié)的普通ASCII字符和占兩個字節(jié)的ANSI字符統(tǒng)統(tǒng)都變成了占三個字節(jié)的Unicode字符螟够,造成了空間的極大浪費。因此Unicode編碼的編碼方式存儲方式分開獨立實現(xiàn)峡钓,存儲傳輸方案專注于實現(xiàn)Unicode編碼如何節(jié)省存儲空間妓笙。
常見的存儲傳輸方案有:UTF-8,UTF-16能岩,UTF-32等

UTF-8方案

UTF-8最大的一個特點寞宫,就是它是一種變長的存儲方式。它可以使用1~4個字節(jié)存儲一個Unicode碼拉鹃,根據(jù)不同的Unicode碼而變化存儲字節(jié)的長度辈赋。
UTF-8的存儲規(guī)則很簡單,只有二條:

  1. 對于小于0x7F的Unicode碼膏燕,UTF-8編碼只有一個字節(jié)钥屈,字節(jié)的第一位設為0,后面7位為Unicode碼坝辫。這也是為了英語字母的UTF-8編碼和普通ASCII碼是相同的篷就。
  2. 對于其他Unicode碼,落入下表的相應的范圍中近忙。其中x代表空白位腻脏,用Unicode碼補充鸦泳。
Unicode符號范圍(十六進制) UTF-8存儲方式(二進制)
000000 ~ 00007F 0xxxxxxx
000080 ~ 0007FF 110xxxxx 10xxxxxx
000800 ~ 00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000 ~ 10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-16方案

UTF-16方案也是一種變長存儲方式,它采用兩個字節(jié)或四個字節(jié)來存儲Unicode碼永品。
當Unicode碼位于編號為00的plane(即0x000000 ~ 0x00FFFF之間)時做鹰,Unicode碼正好對應了兩個字節(jié)(16位二進制)的長度。即使用兩個字節(jié)順序存儲鼎姐。
當Unicode碼位于其他編號的plane(即0x010000 ~ 0x10FFFF)時钾麸,Unicode碼減去0x10000后正好對應成20位二進制,依次填入以下四個字節(jié)的20個空位中:
110110xx xxxxxxxx 110111xx xxxxxxxx
前兩個字節(jié)稱為高位WORD炕桨,以110110開頭饭尝;后兩個字節(jié)稱為低位WORD,以110111開頭献宫。

UTF-32方案

UTF-32方案是一種定長存儲方案钥平,它總是采用4個字節(jié)存儲Unicode碼,由于Unicode碼只有24位姊途,于是UTF-32方案不對Unicode碼做任何變化直接存儲涉瘾。
有人會問,用3個字節(jié)不也是可以完全存儲Unicode的所有編碼嗎捷兰?我個人的理解是立叛,由于Unicode的前身:通用字符集(Universal Character Set, UCS)分為了2字節(jié)編碼的UCS-2和4字節(jié)編碼的UCS-4。為了使編碼方案統(tǒng)一贡茅,UCS-4承諾不再向0x10FFFF之后編碼秘蛇,并由UCS-2作為編號為0的plane(Basic Multilingual Plane, BMP)共同組成Unicode編碼。3者之間的關系為:
UCS-4編碼中0x00000000 ~ 0x0010FFFF的部分組成了Unicode編碼
Unicode編碼中0x000000 ~ 0x00FFFF的部分組成了UCS-2編碼
因此UTF-16作為UCS-2編碼的存儲方案顶考,UTF-32作為UCS-4編碼的存儲方案使用4個字節(jié)赁还,還是仍然保留著。

關于字節(jié)序(Byte Order Mark, BOM)

在UTF-16和UTF-32中存在著Little endian (LE)和Big endian (BE)兩種傳輸字節(jié)流的方式(顯然很蛋疼)
為了讓機器識別出這兩種傳輸方式驹沿,在Unicode編碼規(guī)范中設定了一個叫做"ZERO WIDTH NO-BREAK SPACE"的狀態(tài)位0x00FEFF秽浇,它不對應任何實際含義的字符,且總是出現(xiàn)在文件的開頭甚负,用于標志該文件是使用什么方式讀取字節(jié)流的(LE or BE)柬焕。按照上文三種存儲方案的規(guī)則:

編碼方案 BOM(十六進制)
UTF-8 EF BB BF
UTF-16LE FF FE
UTF-16BE FE FF
UTF-32LE FF FE 00 00
UTF-32BE 00 00 FE FF

可見由于UTF-8不存在LE或BE的區(qū)分,因此它的BOM只有一種梭域,可有可無斑举。所以在UTF-8的方案下,有UTF-8 BOM和UTF-8 無BOM兩種病涨,而它們的區(qū)別僅僅是文件開頭有沒有EF BB BF 這三個字節(jié)罷了

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末富玷,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赎懦,老刑警劉巖雀鹃,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異励两,居然都是意外死亡黎茎,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門当悔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來傅瞻,“玉大人,你說我怎么就攤上這事盲憎⌒峤荆” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵饼疙,是天一觀的道長溺森。 經(jīng)常有香客問我,道長窑眯,這世上最難降的妖魔是什么屏积? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮伸但,結(jié)果婚禮上肾请,老公的妹妹穿的比我還像新娘留搔。我一直安慰自己更胖,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布隔显。 她就那樣靜靜地躺著却妨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪括眠。 梳的紋絲不亂的頭發(fā)上彪标,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音掷豺,去河邊找鬼捞烟。 笑死,一個胖子當著我的面吹牛当船,可吹牛的內(nèi)容都是我干的题画。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼德频,長吁一口氣:“原來是場噩夢啊……” “哼苍息!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤竞思,失蹤者是張志新(化名)和其女友劉穎表谊,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盖喷,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡爆办,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了传蹈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片押逼。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖惦界,靈堂內(nèi)的尸體忽然破棺而出挑格,到底是詐尸還是另有隱情,我是刑警寧澤沾歪,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布漂彤,位于F島的核電站,受9級特大地震影響灾搏,放射性物質(zhì)發(fā)生泄漏挫望。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一狂窑、第九天 我趴在偏房一處隱蔽的房頂上張望媳板。 院中可真熱鬧,春花似錦泉哈、人聲如沸蛉幸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奕纫。三九已至,卻和暖如春烫沙,著一層夾襖步出監(jiān)牢的瞬間匹层,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工锌蓄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留升筏,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓瘸爽,卻偏偏與公主長得像您访,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蝶糯,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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