字符集的三個要素
- 字符表:要顯示的字符的集合(例如所有的英文字符、所有的漢字)
- 字符編碼:字符表中的字符對應的二進制表示
- 字符集:定義了一種規則,將一串二進制數字解釋為一個字符
Unicode編碼
Unicode是計算機科學領域里的一項業界標準。它對世界上大部分的文字系統進行了整理、編碼,使得電腦可以用更為簡單的方式來呈現和處理文字。目前已經編碼了12萬+的字符。—— 維基百科
簡單來說,Unicode就是給世界上存在的字符都賦予唯一的二進制編碼。
Unicode直接做字符集的問題
因為Unicode要編碼所有可能的字符,那么每個字符占用的字節長度就會變多。以英文為例,一個英文字符使用ASCII碼只需要一個字節,而用Unicode需要4個字節,甚至更多。并且前面的字節都是0。這樣純英文文件的存儲大小就會成倍擴大,是極大的浪費。
UTF-8編碼
一種變長的編碼方式,基于Unicode的一種實現。它使用1--4個字節表示一個字符,根據不同的字符變化字節的長度,可以節省空間。編碼規則如下:
- 對于單字節的字符,字節的第一位設為0,后面7位是這個字符的unicode碼。ASCII碼表中的字符,UTF-8編碼與其ASCII碼保持一致。
- 對于n個字節的字符(n>1),第一個字節的前n位都設為1,第n+1位設為0,后面字節的前兩位均設為10。剩余的二進制位,從后向前填上這個符號的unicode碼。用0填充未使用的二進制位。
Unicode范圍 | 編碼格式 | 剩余位數 |
---|---|---|
000000 – 00007F | 0xxxxxxx | 7位 |
000080 – 0007FF | 110xxxxx 10xxxxxx | 11位 |
000800 – 00FFFF | 1110xxxx 10xxxxxx 10xxxxxx | 16位 |
010000 – 10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 21位 |
根據上表可以看出,UTF-8剩余可以填的位數,決定了對應Unicode編碼的范圍。 下面舉個轉換的例子:
"樊"的unicode是6A0A(0110 1010 0000 1010),查表可知,6A0A屬于第三行的范圍,因此"樊"的UTF-8編碼需要三個字節,即格式是 1110xxxx 10xxxxxx 10xxxxxx 。然后,從6A 0A的最后一個二進制位開始,從后向前填入格式中的x,多出的位補0。最終,"樊"的UTF-8編碼是11100110 10101000 10001010(E6 A8 8A)
由此可以總結出字符用UTF-8編碼的規律:
- 4個字節的UTF-8十六進制編碼一定是以F開頭
- 3個字節的UTF-8十六進制編碼一定是以E開頭
- 2個字節的UTF-8十六進制編碼一定是以C或D開頭
- 1個字節的UTF-8十六進制編碼一定是以小于8的數字開頭
注:UTF-8并沒有編碼所有的Unicode的字符,只包含了第0號平面(plane)和部分1號平面的字符。這屬于更深層次的探究,感興趣的讀者可以通過UTF-8與Unicode字符平面映射了解。
中文編碼
GB2312
該字符集使用2個字節表示一個字符。簡單地理解,一個小于127的字節的意義與ASCII碼相同,但兩個大于127的字節連在一起時,就是GB2312編碼的字符。以下是兩個字節的具體范圍:
第一個字節的范圍是0xA1(161)–0xF7(247) ; 第二個字節的范圍是0xA1(161)–0xFE(254)
共收錄了6763個漢字,還包括拉丁字母、希臘字母、日文字符。并對 ASCII 里已有的數字、標點、字母賦予了兩個字節的編碼,這就是”全角”字符,而小于127的就稱為”半角”字符。
GBK
由于GB2312僅包含了常用漢字,沒有編碼生僻字以及繁體字,GBK就對其進行了擴展。簡單地理解,只要第一個字節大于127,不管后面的字節是否大于127,就是GBK編碼的字符。以下是兩個字節的具體范圍:
第一個字節的范圍是0x81(129)–0xFE(254) ; 第二個字節范圍一部分在0x40(64)–0x7E(126),另一部分在0x80(128)–0xFE(254)
這樣擴展之后的編碼方案被稱為 GBK 標準,GBK包括了GB2312 的所有內容,提供了23940個編碼,使用了21886個。
中文編碼的存在價值
UTF-8編碼漢字通常需要三個字節,而GBK只需要兩個字節,所以對于純中文、不考慮國際化,且對流量和存儲大小比較敏感的應用,可以使用GBK編碼節省存儲空間和傳輸流量。
參考資料
原博文發布在個人博客,歡迎訪問!!