字符編碼(一)

最近在看書的時候突然糾結(jié)于Unicode相關(guān)字符編碼,查了一些資料偎血,并寫了這篇文章,順帶做下筆記盯漂,希望能幫到一些人颇玷。文章如果有寫的不妥的或者不正確的地方還請大家糾正。

Unicode 編碼

Unicode是一個符號集就缆,它對世界上大部分的文字系統(tǒng)進行了整理帖渠、編碼,使得電腦可以用更為簡單的方式來呈現(xiàn)和處理文字竭宰。解決傳統(tǒng)的字符編碼方案的局限空郊。

歷史上存在兩個獨立的嘗試創(chuàng)立單一字符集的組織份招,即國際標(biāo)準(zhǔn)化組織(ISO)和非營利機構(gòu)統(tǒng)一碼聯(lián)盟。前者開發(fā)的 ISO/IEC 10646 項目狞甚,后者開發(fā)的統(tǒng)一碼項目脾还。因此最初制定了不同的標(biāo)準(zhǔn)。他們不久便發(fā)現(xiàn)對方的存在入愧,大家為著相同的目的而工作鄙漏,最后他們合并雙方的工作成果。統(tǒng)一碼(Unicode)的編碼方式與ISO 10646的通用字符集(Universal Character Set, 簡稱UCS)概念相對應(yīng)棺蛛。

統(tǒng)一碼的編碼方式使用16位編碼空間怔蚌,也就是每個字符占用2個字節(jié),最多可表示2^(16)個字符旁赊,基本滿足各種語言的需求桦踊,且實際上16為編碼空間并未完全使用,其中保留了大量空間作為未來備用终畅。這里所說的16位編碼空間即統(tǒng)一碼的0號平面(也稱“基本多文種平面”籍胯,Basic Multilingual Plane,簡稱BMP)离福,目前統(tǒng)一碼版本中另外定義了16個輔助平面杖狼,這樣就需求21位編碼空間,即 16+5 位妖爷,一共17個平面(不局限于)蝶涩,每個平面擁有2^(16)個代碼點。如下表所示(摘自Wikipedia):

unicode-plane.png

ASCII

ASCII(“阿斯柯”) 是國際上普遍采用的一種字符編碼系統(tǒng)絮识,由8位二進制進行編碼绿聘,最高位恒為0,因此可以定義128個字符次舌,其中包括10個十進制數(shù)字熄攘、52個英文大小寫字母(A~Z, a~z)等。

UTF-8

UTF(Unicode Transformation Format, Unicode字符集轉(zhuǎn)換格式)彼念,UTF-7挪圾、UTF-8、UTF-16国拇、UTF-32洛史、GB18030...只是Unicode的一種實現(xiàn)方式惯殊,即怎樣將 Unicode 定義的數(shù)字轉(zhuǎn)換成程序數(shù)據(jù)酱吝。

UTF-8 編碼,以8位無符號整數(shù)為單位進行編碼土思,是針對Unicode的可變長字符編碼务热,UTF-8 是 ASCII 編碼的父集忆嗜,也就是說,UTF-8 與 ASCII 編碼兼容崎岂,如:對于0x000000-0x00007F之間的字符捆毫,即前128個字符,UTF-8 編碼與 ASCII 編碼完全相同冲甘。這使得原來處理 ASCII 碼字符的軟件無須或只須做少部分修改绩卤,即可繼續(xù)使用,UTF-8 編碼應(yīng)用廣泛江醇,基本所有互聯(lián)網(wǎng)協(xié)議都支持 UTF-8 編碼濒憋,是目前編碼方式中優(yōu)先采用的方式之一。

關(guān)于Unicode 與 UTF-8 編碼之間的轉(zhuǎn)換關(guān)系陶夜,如下表所示:

Unicode 標(biāo)量值(0x) UTF-8(0b) 備注
000000-00007F 0xxxxxxx 與ASCII編碼字符相對應(yīng)凛驮,最高位恒為0。占用一個字節(jié)
000080-0007FF 110xxxxx-10xxxxxx 第一個字節(jié)由110開始条辟,接著的字節(jié)由10開始黔夭。占用兩個字節(jié)
000800-00D7FF 1110xxxx-10xxxxxx-10xxxxxx 占用3個字節(jié)
00D800-00DFFF - D800-DBFF 代表 UTF-16的高半?yún)^(qū)。DC00-DFFF 代表 UTF-16的低半?yún)^(qū)
00E000-00FFFF 1110xxxx-10xxxxxx-10xxxxxx 占用3個字節(jié)
010000-10FFFF 11110xxx-10xxxxxx-10xxxxxx-10xxxxxx 最高字節(jié)前1的數(shù)量代表字節(jié)數(shù)羽嫡,如:1110即3個字節(jié)本姥。占用4個字節(jié)

在基本多文種平面中約定00D800-00DFFF這范圍用于UTF-16擴展標(biāo)識輔助平面(即低位兩個字節(jié)),在UTF-16 中會詳細(xì)介紹杭棵。

舉個例子扣草,漢字“聽”的 Unicode 編碼是U+542C,轉(zhuǎn)成UTF-8颜屠,步驟如下:

  1. 由上表可得出辰妙,“聽”字的 Unicode 編碼屬于U+0800到U+D7FF區(qū)域,說明該字占用3個字節(jié)甫窟,按照1110xxxx-10xxxxxx-10xxxxxx進行填充密浑。
  2. U+542C換算成二進制:0101-0100-0010-1100。
  3. 從低位向高位填充粗井,代替x尔破,11100101-10010000-10101100。
  4. 得出漢字“聽”的UTF-8編碼:0xE590AC浇衬。

從Unicode 2.0開始懒构,Unicode采用了與ISO 10646-1相同的字庫和字碼;ISO也承諾耘擂,ISO 10646將不會替超出U+10FFFF的UCS-4編碼賦值胆剧,以使得兩者保持一致。2003年11月 UTF-8 被 RFC 3629重新規(guī)范,只能使用原來Unicode定義的區(qū)域秩霍,U+0000到U+10FFFF篙悯。如果以上都能理解,那么下表就非常好理解了(摘自Wikipedia):

unicode-scalar-illegality.png

之前有較多的人在微博上私信我@tingxins铃绒,關(guān)于這表格鸽照,疑惑頗多,因此在此處進行補充并簡單解釋一下颠悬,希望能幫到讀者矮燎。C0,C1非常好理解赔癌,不再詳述漏峰。我們來看看F5-FF的頭字節(jié),為什么是非法的届榄?我們可以以 U+10FFFF 為例浅乔,轉(zhuǎn)UTF-8編碼后,可以得出頭字節(jié)二進制流為11110100铝条,即F4靖苇,基于 RFC 3629 規(guī)范,因此可得出大于F4頭字節(jié)的可以理解成非法的或者不可能出現(xiàn)的編碼班缰,就7或8字節(jié)序列的頭字節(jié)而言贤壁,更是違反了早期UTF-8編碼不可超過6字節(jié)序列的規(guī)范。(更新于 2017-2-18

UTF-8 小結(jié)

  1. 在UTF-8文件的開首埠忘,以EF,BB,BF代表脾拆,以顯示這個文本文件是以UTF-8編碼。
  2. 字節(jié)0xFE和0xFF在UTF-8編碼中從未用到莹妒,同時名船,UTF-8以字節(jié)為編碼單元,它的字節(jié)順序在所有系統(tǒng)中都是一様?shù)闹嫉。瑳]有字節(jié)序的問題渠驼,也因此它實際上并不需要BOM(字節(jié)順序標(biāo)記,Byte-Order Mark)鉴腻,但在UTF-16中用來標(biāo)記存儲方式(大端小端)迷扇。
  3. ASCII和UTF-8兩種編碼方式下是一樣的,可以說UTF-8是ASCII編碼的父集爽哎。

現(xiàn)在我們已經(jīng)知道了UTF-8的含義蜓席,以及其編碼原理,下面我們來探究一下 UTF-16 編碼方式课锌。

UTF-16

UTF-16 編碼厨内,以16位無符號整數(shù)為單位進行編碼。上文中所提及到的“基本多文種平面”的編碼空間中保留了一塊區(qū)域(從U+D800到U+DFFF),該區(qū)域不映射Unicode字符隘庄,UTF-16就是利用保留下來的0xD800-0xDFFF編碼空間來對U+10000到U+10FFFF(即輔助平面)進行字符映射的。

在 UTF-16 編碼中癣亚,從U+0000至U+D7FF以及從U+E000至U+FFFF的編碼空間的映射關(guān)系同 Unicode丑掺,相對應(yīng)于ISO通用字符集中的USC-2。從U+10000到U+10FFFF的編碼空間述雾,UTF-16用一對16比特長的碼元(即32bit,4Bytes)進行編碼街州,熟稱代理對(Surrogate Pair).

0xD800-0xDFFF編碼空間分成兩部分(即上述所說的代理對):

  1. UTF-16的高位代理:從U+D800至U+DBFF,也稱前導(dǎo)代理(lead surrogates)玻孟。
  2. UTF-16的低位代理:從U+DC00至U+DFFF唆缴,也稱后尾代理(trail surrogates)。

UTF-16 輔助平面編碼方式比較巧妙黍翎,從U+10000到U+10FFFF面徽,共計FFFFF個,即2(20)個匣掸,至少需要20位來表示趟紊,我們再來看代理對,先看高半?yún)^(qū)碰酝,從U+D800到U+DBFF霎匈,共計3FF個,即2(10)個送爸,同理低半?yún)^(qū)也是2(10)個铛嘱,正好為2(20)個代理對,這也是“基本多語言平面”中保留不對應(yīng)于Unicode字符的2048個碼位的原因袭厂。下面我們來看一張表:

lead S \ trail S DC00 DC01 DC02 ... DFFF
D800 10000 10001 10002 ... 103FF
D801 10400 10401 10402 ... 107FF
D802 10800 10801 10802 ... 10BFF
? ? ? ? ? ?
DBFF 10FC00 10FC01 10FC02 ... 10FFFF

舉個例子墨吓,古意大利字母"??"的Unicode編碼為U+10300,轉(zhuǎn)成UTF-16纹磺,步驟如下:

  1. 在0x10300的基礎(chǔ)上先減去0x10000 --> 0x00300肛真,轉(zhuǎn)成二進制:0000-0000-0011-0000-0000。
  2. 得出高10位(0000-0000-00)和低10位(11-0000-0000)
  3. 添加0xD800到高10位(不足補0)爽航,得出UTF-16高位:0xD800 + 0x0000 --> 0xD800
  4. 添加0xDC00到低10位(不足補0)蚓让,得出UTF-16低位:0xDC00 + 0x0300 --> 0xDF00
  5. 得出古意大利字母"??"的UTF-16BE編碼:U+D800DF00

關(guān)于Unicode 與 UTF-16 編碼之間的轉(zhuǎn)換關(guān)系,如下表所示:

Unicode 標(biāo)量值(0x) UTF-16(0b) 備注
U+0000-U+FFFF xxxxxxxx xxxxxxxx 占用兩個字節(jié)讥珍,同 Unicode
U+10000-U+10FFFF 110110xxxxxxxxxx 110111xxxxxxxxxx 占用四個字節(jié)

由上表可看出历极,UTF-16無法兼容ASCII編碼。

UTF-16 存儲形式

想必讀者現(xiàn)在有這樣一個疑惑衷佃,UTF-16 是以16位無符號整數(shù)位單位進行編碼趟卸,即每個字符占用兩個字節(jié),如:在Mac和Window上,對字節(jié)順序的理解是不一樣的锄列,這時就出現(xiàn)了一個問題图云,同一字節(jié)流可能會被解釋為不同內(nèi)容,以字符“心“為例邻邮,該字符十六進制編碼為U+5FC3竣况,按兩個字節(jié)進行拆分:5F和C3,在Mac上讀取時是從低字節(jié)開始筒严,那么在Mac OS會認(rèn)為此U+5FC3編碼為U+C35F丹泉,顯示字符為"?",而在Windows上從高字節(jié)開始讀取鸭蛙,則編碼為U+5FC3的字符為“心”摹恨。為了解決該問題,字節(jié)順序標(biāo)記(Byte-Order Mark, BOM)誕生娶视,字符U+FEFF如果出現(xiàn)在字節(jié)流的開頭晒哄,則用來標(biāo)識該字節(jié)流的字節(jié)序,是高位在前還是低位在前肪获,反之同理揩晴。這兩種字節(jié)序在計算機我們通常稱大端和小端,下面我們來繼續(xù)探究一下贪磺。

大端存儲和小端存儲

大端存儲(Big Endian, 簡稱BE):一個字中的高位字節(jié)放在內(nèi)存中這個字區(qū)域的低地址硫兰。小端存儲(Little Endian, 簡稱LE):即一個字中的低位字節(jié)放在內(nèi)存中這個字區(qū)域的低地址處。

還是以古意大利字母"??"為例寒锚,我們剛已計算出其UTF-16編碼為U+D800DF00劫映,如果采用大端存儲,編碼存儲的序列為D800 DF00刹前,采用小端存儲泳赋,則為00D8 00DF。這個兩個存儲模式的區(qū)別在于字中字節(jié)的存儲順序不同喇喉,而字的存儲順序是相同的祖今。再看幾個例子(摘自Wikipedia):

unicode-endian.png

UTF-16 小結(jié)

  1. 在UTF-16文件的開首,以FEFF 或者 FFFE代表拣技,以顯示這個文本文件是以BE存儲編碼還是以LE存儲編碼千诬。
  2. UTF-16編碼可以說是UCS-2的父集,對于小于0x10000的Unicode碼膏斤,UTF-16編碼就等于UCS碼徐绑,也可以說UTF-16編碼就等于Unicode標(biāo)量值。
  3. UTF-16 VS UTF-8莫辨,個人覺得這兩種編碼方式?jīng)]有可比性傲茄,主要取決于字符本身主要集中在哪個平面毅访,兩者都是可變長度編碼。
  4. UTF-16 VS UCS-2[1]盘榨,如果這個字超過U+FFFF(如:U+10000至U+10FFFF)喻粹,那么就無法用UCS-2的格式編碼,UTF-16可看成是UCS-2的父集草巡。

相關(guān)文章及鏈接

  1. 字符編碼筆記:ASCII守呜,Unicode和UTF-8
  2. Unicode Wikipedia
  3. UTF-8 Wikipedia
  4. 字節(jié)順序標(biāo)記 Wikipedia
  5. UTF-16 Wikipedia
  6. Unicode 字符平面映射

  1. UCS即ISO 10646的通用字符集(Universal Character Set, 簡稱UCS),UCS-2我們可以簡單理解為UTF-16捷犹,同樣使用16位的編碼空間弛饭。 ?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冕末,一起剝皮案震驚了整個濱河市萍歉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌档桃,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異创千,居然都是意外死亡间学,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評論 3 399
  • 文/潘曉璐 我一進店門嘹屯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攻询,“玉大人,你說我怎么就攤上這事州弟【埽” “怎么了?”我有些...
    開封第一講書人閱讀 169,716評論 0 364
  • 文/不壞的土叔 我叫張陵婆翔,是天一觀的道長拯杠。 經(jīng)常有香客問我,道長啃奴,這世上最難降的妖魔是什么潭陪? 我笑而不...
    開封第一講書人閱讀 60,222評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮最蕾,結(jié)果婚禮上依溯,老公的妹妹穿的比我還像新娘。我一直安慰自己瘟则,他們只是感情好誓沸,可當(dāng)我...
    茶點故事閱讀 69,223評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著壹粟,像睡著了一般拜隧。 火紅的嫁衣襯著肌膚如雪宿百。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,807評論 1 314
  • 那天洪添,我揣著相機與錄音垦页,去河邊找鬼。 笑死干奢,一個胖子當(dāng)著我的面吹牛痊焊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忿峻,決...
    沈念sama閱讀 41,235評論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼薄啥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了逛尚?” 一聲冷哼從身側(cè)響起垄惧,我...
    開封第一講書人閱讀 40,189評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绰寞,沒想到半個月后到逊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,712評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡滤钱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,775評論 3 343
  • 正文 我和宋清朗相戀三年觉壶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片件缸。...
    茶點故事閱讀 40,926評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡铜靶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出他炊,到底是詐尸還是另有隱情争剿,我是刑警寧澤,帶...
    沈念sama閱讀 36,580評論 5 351
  • 正文 年R本政府宣布佑稠,位于F島的核電站秒梅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏舌胶。R本人自食惡果不足惜捆蜀,卻給世界環(huán)境...
    茶點故事閱讀 42,259評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望幔嫂。 院中可真熱鬧辆它,春花似錦、人聲如沸履恩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽切心。三九已至飒筑,卻和暖如春片吊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背协屡。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評論 1 274
  • 我被黑心中介騙來泰國打工俏脊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肤晓。 一個月前我還...
    沈念sama閱讀 49,368評論 3 379
  • 正文 我出身青樓爷贫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親补憾。 傳聞我的和親對象是個殘疾皇子漫萄,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,930評論 2 361

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