字符集與字符編碼

從一個問題提及算法

爲何計算字符串的長度的時候會把中文當作2個字符,英文當成一個字符來計算?數組

基本概念

字符

在計算機中,字符是一個信息單位。簡單來講就是一個漢字或者一個英文,一個標點符號。網絡

字符集

顧名思義,字符集就是字符的集合。編碼

字符編碼

字符編碼就是把字符集中的字符編碼爲指定集合中的某一對象,以便在計算機中存儲和經過網絡傳遞。3d

碼元

是指一個已編碼的文本中具備最短比特組合的單元。對於UTF-8來講碼元是8比特長。對於UTF-16來講,碼元是16比特長。對於UTF-32來講,碼元是32比特長。代理

字符編碼由如下幾個關鍵元素構成:code

  • 抽象字符表(Abstract character repertoire): 是一個系統支持的全部抽象字符的集合,簡單點說就是有哪些字符。
  • 編碼字符集(Coded Character Set): 是將字符集 C中每一個字符映射到1個座標(整數值對:x, y)或者表示爲1個非負整數 ,簡單點說就是字符的編號。
  • 字符編碼表(Character Encoding Form): 是將編碼字符集中的非負整數值轉換成有限比特流長度整型值(碼元)的序列。簡單點說就是這些編號如何編碼成一系列的碼元。
  • 字符編碼方案(Character Encoding Scheme): 這些單元如何組成八位子節流。 好比在Unicode的場合,使用一個簡單的字符來制定字節的順序是大端序或者小端序。(UTF-8不須要專門指明字節序) 有些複雜的字符編碼機制(如ISO/IEC 2022)使用控制字符轉義序列在幾種編碼字符集或者用於減少每一個單元所用的字節數的壓縮機只之間切換

首先了解一下字符編碼的歷史

ASCII碼-1967

全稱是American Standard Code for Information Interchange,譯作美國信息交換標準代碼。這套字符集在1967年被正式公佈。orm

它一共包含128種字符,其中33個控制字符,95個可顯示的字符。正好是一個字節的低7位,最高位置0。cdn

下圖是一個ASCII碼的表格: 對象

EASCII碼 與 ISO 8859 - 1985

剛開始計算機只在美國使用,因此128個字符是夠用的,可是隨着科技的發展歐洲的國家也開始使用上了計算機。這時候出現了問題,128個字符不夠用了。好比法語中有注音符號,因而一些歐洲國家決定利用字節中閒置的最高位編入新的符號。 這樣就在ASCII碼的基礎上,既保證了對ASCII碼的兼容性,又補充擴展了新的字符,因而就稱之爲Extended ASCII(擴展ASCII)碼,簡稱EASCII碼。

在EASCII碼中,當第一個比特位(即字節的最高位)爲0時,仍表示以前那些經常使用的ASCII字符(實際的二進制編碼爲0000 0000 ~ 0111 1111,對應的十進制就是0~127),而爲1時就表示補充擴展的其餘衍生字符(實際的二進制編碼爲1000 0000 ~ 1111 1111,對應的十進制就是128~255)。

EASCII的擴展部分以下圖: [image:DA4EFEE5-575B-4D69-AB85-0D6A0963052E-55654-00029E64D82D4B45/18408A67-1AF3-4473-AE8A-E7E6DE1C355B.png]

可是有這樣想法的國家有不少,因此還有另外一套標準就是ISO 8859。

ISO 8859 是一組字符集的總稱,其下共包含了15個字符集,即ISO 8859-n ,其中n=1,2,3…11,13,14,15,16

這兩種編碼方式都是前128位兼容ASCII碼,後128位本身定義。

GB2312 - 1981

後來計算機進入了中國,EASCII碼也不夠用了。要知道,漢字是世界上包含符號最多的文字。因而⌈中國國家標準總局⌋(現已改名爲⌈國家標準化管理委員會⌋)在1981年,正式制訂了中華人民共和國國家標準簡體中文字符集,全稱《信息交換用漢字編碼字符集·基本集》,項目代號爲GB 2312 或 GB 2312-80(GB爲國標漢語拼音的首字母),此套字符集於當年的5月1日起正式實施。

GB2312編碼爲了不與ASCII字符編碼(0~127)相沖突,規定表示一個漢字的編碼(即漢字內碼)的字節其值必須大於127(即字節的最高位爲1),而且必須是兩個大於127的字節連在一塊兒來共同表示一個漢字(GB2312爲雙字節編碼),前一字節稱爲高字節,後一字節稱爲低字節;而一個字節的值若小於127(即字節的最高位爲0),天然是仍表示一個原來的ASCII字符(ASCII爲單字節編碼)。

所以,能夠認爲GB2312是對ASCII的中文擴展(即GB2312與ASCII相兼容),正如EASCII是對ASCII的歐洲文字擴展同樣。

不過,很顯然的是,GB2312與EASCII碼的128~255這段擴展部分所表示的字符是不一樣的。也就是說,GB2312與EASCII雖然都兼容ASCII,但GB2312並不兼容EASCII的擴展部分。

事實上,目前世界上除ASCII以外的其它通行的字符編碼方案,基本上都兼容ASCII,但相互之間並不兼容。

GB2312中,多是出於顯示上視覺美觀的考慮,除漢字以外的682個字符中,甚至包括了ASCII裏原本就有的數字、標點、字母等字符。也就是說,這些ASCII裏原來就有的單字節編碼的字符,又再編了兩個字節長的GB2312編碼版本。這682個字符就是常說的「全角」字符,而這682個字符中所對應的ASCII字符就被稱之爲「半角」字符。

Unicode

上面說了這麼多種編碼,每一個國家都有本身的編碼標準,以便能在計算機上正確的顯示本身國家的符號。可是不一樣國家地區互相不能正確顯示。因此有2個組織來嘗試指定統一的編碼標準。

  • 國際標準化組織(ISO)
  • 統一碼聯盟 國際標準化組織(ISO)及國際電工委員會(IEC)於1984年聯合成立了ISO/IEC小組,主要用於開發統一編碼項目; 而Xerox、Apple等軟件製造商則於1988年組成了統一碼聯盟,用於開發統一碼項目。 兩個組織都在編寫統一字符集,但後來他們發現各自在作相同的工做,同時世界上也不須要兩個不兼容的字符集,因而兩個組織就此合併了雙方的工做成果,併爲創立一個單一編碼表而協同工做。

1991年,兩個組織共同的工做成果Unicode 1.0正式發佈,不過Unicode 1.0並不包含CJK字符(即中日韓)。

GB13000 - 1993

1993年時,包含CJK的Unicode 1.1已經發布了,因而在同一年,中國大陸制定了幾乎等同於Unicode1.1的GB13000.1-93國家編碼標準(簡稱GB13000)。是的,你沒聽錯,中華人民共和國信息產業部把Unicode裏的全部東東拿過來,而後本身從新修訂發佈了下,改成了國家標準GB13000。此標準等同於 ISO/IEC 10646.1:1993和Unicode 1.1。

GBK - 1995

GB2312 基本覆蓋了中國大陸99%以上的使用頻率,基本知足了漢字的計算機處理須要。但對人名,生僻字等並不能處理。

因而,利用GB2312未使用的碼點空間,收錄這些字符,於1995年又發佈了《漢字內碼擴展規範(GBK)》。其中K是擴展的意思。

GBK跟GB2312同樣是雙字節編碼,然而,GBK只要求第一個字節即高字節是大於127就固定表示這是一個漢字的開始(0~127固然表示的仍是ASCII字符),再也不要求第二個字節即低字節也必須是127號以後的編碼。這樣,做爲一樣是雙字節編碼的GBK才能夠收錄比GB2312更多字符。

因此GB系列的編碼方案中,一個漢字是由2個字節組成,一個英文是由一個字節組成。

接下來詳細討論一下Unicode的編碼方案

USC-2 和 USC-4

顧名思義,UCS-2就是用兩個字節編碼,UCS-4就是用4個字節(實際上只用了31位,最高位必須爲0)編碼

UTF-8

是Unicode的一種實現方式。是一種可變長度的編碼方式。它可使用1~4個字節表示一個符號,根據不一樣的符號來變化字節長度。 編碼規則:

  • 對於單字節符號,字節的第一位設爲0,後面7位爲這個符號的Unicode碼
  • 對於n(n>1)字節的符號,第一個字節的前n位都設爲1,第n+1位設爲0,後面的字節得前2位一概設爲10。剩下的二進制位所有爲這個符號的Unicode碼。

編碼實現:

根據編碼規則,同理能夠推出解碼規則:

舉個例子: 0xxxxxxx 110xxxxx 10xxxxxx 1110xxxx 10xxxxxx 10xxxxxx 1110xxx 10xxxxxx 10xxxxxx 10xxxxxx

UTF-16

也是Unicode的一種實現方式。是把Unicode字符集的抽象碼位映射爲16位長的整數(碼元)的序列。須要1~2個16位長的碼元來表示,因此這是一個邊長表示。

Unicode的編碼空間從U+0000到U+10FFFF,共有1,112,064個碼位(code point)可用來映射字符。Unicode的編碼空間能夠劃分爲17個平面(Plane),每一個平面包含2^16(65536)個碼位。17個平面的碼位可表示爲從U+xx0000 到 U+xxFFFF,其中xx表示十六進制從00到10。第一個平面稱爲基本多語言平面(Basic Multilingual Plane, BMP),或稱第零平面(Plane 0)。其餘平面稱爲輔助平面(Supplementary Planes)。基本多語言平面內,從U+D800到U+DFFF之間的碼位區塊是永久保留不映射到Unicode字符。UTF-16就利用保留下來的0xD800-0xDFFF區段的碼位來對輔助平面的字符的碼位進行編碼。

編碼規則: U+0000 ~ U+D7FF 和 U+E000 ~ U+FFFF 這個範圍即基本多語言平面(Basic Multilingual Plane, BMP),包含了最經常使用的字符,包含的碼位範圍是U+0000 到 U+FFFF,只須要一個16位的碼元便可表示。

U+10000 ~ U+10FFFF 其它平面(叫作輔助平面,Supplementary Planes)中的碼位,在UTF-16中被編碼爲一對16比特長的碼元(即32bit,4Bytes),稱做代理對(surrogate pair),具體方法是:

  • 碼位(0x10000~0x10FFFF)減去0x10000(BMP範圍),剩下20比特長的數字,範圍是0..0xFFFFF。
  • 高位的10比特(數值範圍爲0..0x03FF)被加上0xD800獲得第一個16位長的碼元或稱做高位代理(high surrogate),值的範圍是0xD800..0xDBFF。
  • 低位的10比特的值(值的範圍也是0..0x3FF)被加上0xDC00獲得第二個16位長的碼元或稱做低位代理(low surrogate),如今值的範圍是0xDC00..0xDFFF。

上述算法可理解爲:輔助平面中的碼位從U+10000到U+10FFFF,共計FFFFF個,即2^20=1,048,576個,須要20位來表示。若是用兩個16位長的整數組成的序列來表示,第一個整數(稱爲前導代理)要容納上述20位的前10位,第二個整數(稱爲後尾代理)容納上述20位的後10位。還要能根據16位整數的值直接判明屬於前導整數代理的值的範圍(2^10=1024),仍是後尾整數代理的值的範圍(也是2^10=1024)。所以,須要在基本多語言平面中保留不對應於Unicode字符的2048個碼位,就足以容納前導代理與後尾代理所須要的編碼空間。這對於基本多語言平面總計65536個碼位來講,僅佔3.125%.

編碼規則實現:

根據UTF-16的編碼規則,同理能夠獲得解碼規則,下圖是從Swift源碼中截取的UTF-16的解碼代碼: [image:69D26150-1CDC-4E9D-B94E-916136C27353-55654-0002535098FC388A/46208888-62B3-4137-95AE-A697AFD5B43A.png]

舉個例子: 例如U+10437編碼(𐐷)

  • 0x10437減去0x10000,結果爲0x00437,二進制爲0000 0000 0100 0011 0111。
  • 分區它的上10位值和下10位值(使用二進制):0000000001 and 0000110111。
  • 添加0xD800到上值,以造成高位:0xD800 + 0x0001 = 0xD801。
  • 添加0xDC00到下值,以造成低位:0xDC00 + 0x0037 = 0xDC37。

UTF-16比起UTF-8,好處在於大部分字符都以固定長度(2字節)存儲,可是UTF-16沒法兼容ASCII碼。

思考問題:

一、Unicode與UTF-8 16 有什麼區別?

二、爲何UTF-8不須要專門指明字節序?

三、爲何計算字符個數會把英文當成一箇中文當成兩個?

四、咱們常說的Unicode編碼指的是什麼?

相關文章
相關標籤/搜索