徹底搞明白 Gb2312、Gbk 和 Gb18030
本文轉載自微信公眾號「Linux開發那些事兒」,作者LinuxThings。轉載本文請聯系Linux開發那些事兒公眾號。
日常工作的過程中,關于字符編碼的問題經常讓人頭疼不已,這篇文章就來捋一捋關于 GB2312、GBK、GB18030 相關的知識 以及它們和 Unicode 的關系。
簡介
- GB2312
1980 年,中國發布了第一個漢字編碼標準,也即 GB2312 ,全稱 《信息交換用漢字編碼字符集·基本集》,通常簡稱 GB (“國標”漢語拼音首字母), 共收錄了 6763 個常用的漢字和字符,此標準于次年5月實施,它滿足了日常 99% 漢字的使用需求
- GBK
由于有些漢字是在 GB2312 標準發布之后才簡化的,還有一些人名、繁體字、日語和朝鮮語中的漢字也沒有包括在內,所以,在 GB2312 的基礎上添加了這部分字符,就形成了 GBK ,全稱 《漢字內碼擴展規范》,共收錄了兩萬多個漢字和字符,它完全兼容 GB2312
GBK 于 1995 年發布,不過它只是 "技術規范指導性文件",并不屬于國家標準
- GB18030
GB18030 全稱《信息技術 中文編碼字符集》 ,共收錄七萬多個漢字和字符, 它在 GBK 的基礎上增加了中日韓語中的漢字 和 少數民族的文字及字符,完全兼容 GB2312,基本兼容 GBK
GB18030 發布過兩個版本,第一版于 2000 年發布,稱為 GB18030-2000,第二版于 2005 年發布,稱為 GB18030-2005
編碼方式
ASICII、GB2312、GBK、GB18030 之間的關系可以用下圖表示
GB2312 兼容 ASICII 編碼, GBK 兼容 GB2312 編碼,GB18030 兼容 GB2312 編碼 和 GBK 編碼
實際生活中,我們用到的 99% 的漢字,都屬于 GB2312 編碼范圍 ,GB2312 每個編碼對應的是哪個漢字可以參考 GB2312簡體中文編碼表, GBK 編碼可以參考 GBK編碼表, GB18030 可以參考 GB18030-2005 文檔
GB2312 編碼
GB2312 把每個漢字都編碼成兩個字節,第一個字節是高位字節,第二個字節是低位字節
GB2312 為了兼容 ASICII ,其編碼需要進行一些轉換才能避免和 ASICII 編碼重疊,轉換的過程涉及到區位碼和國標碼的概念,下面說明轉成內碼的過程
- 區位碼
GB2312 對漢字進行了分區處理,每個區含有 94 個漢字或者字符,總共有 94 個區,每個漢字或者字符都對應一個 分區編號和分區內的位置編號,稱為 區位碼
比如:漢字 "中" 字的 分區編號是 54,分區內位置編號是 48,所以,"中" 字的區位碼是 54 48
- 國標碼
國標碼 也叫 交換碼,用于交換文件所使用的編碼,在早期,不同的操作系統可能使用不同的內碼,如果它們之間要交換文件,則會發生亂碼的現象,當時的解決方法是交換文件之前先轉成交換碼再交換,接收者收到之后再轉成內碼
交換碼是比較早期的一種方案,目前系統大都采用內碼作為交換碼
ASICII 碼為 0- 31 的這 32 個字符是不可顯示的字符,為了避免和這些字符的碼點沖突,將 分區編號和分區內位置編號都加上 32 ,把這個轉換的結果稱為 國標碼
比如:漢字 "中" 字分區編號是 54,分區內位置編號是 48,加上 32 之后,分區編號是 54 + 32 = 86, ,分區內位置編號是 48 + 32 = 80,所以 "中" 字 的國標碼是 86 80
- 內碼
國標碼 和 ASICII 碼還是存在一定的重復,比如 "中" 字 的國標碼是 86 80,對應第一個字節是 86,第二個字節是 80,而在 ASICII 碼中它們分別代表大寫字母V 和 大寫字母 P,這就無法區分它們到底是一個漢字,還是兩個字母
為了解決這一點,把國標碼中的每個字節的最高位置為 1,也即相當于每個字節都加上 128 ( 2的7次方 ),還是以 "中" 字為例,它的 國標碼是 86 80,加上 128 后, 第一個字節是 86 + 128 = 214, 第二個字節是 80 + 128 = 208,轉化成 16 進制是 0xD6 0xD0 ( 214 的十六進制是 0xD6, 208 的十六進制是 0xD0 )
國標碼的每個字節都加上 128 后,得到國標碼的機內碼,簡稱 內碼,漢字是以內碼的形式在計算機中存儲和傳播的
上面介紹 區位碼 和 國標碼,主要是是為了說明 漢字內碼是如何一步一步發展而來的
可以看出,漢字的 區位碼 + 32 + 128 就得到了內碼,進一步簡化,區位碼 + 32 + 128 = 區位碼 + 160 = 區位碼 + 0xA0(128 的十六進制) , 因此 內碼 = 區位碼 + 0xA0
比如:"中" 字的區位碼是 54 48,對應的十六進制是0x36 0x30,因此它的內碼為 (0x36 + 0xA0) (0x30 + 0xA0),也即 0xD6 0xD0
關于漢字的區位碼請參考:漢字區位碼
GB2312 有效的編碼范圍如下圖所示
上圖中 紅色欄 表示 ASICII 的編碼范圍,綠色欄表示 GB2312 編碼范圍
GBK 編碼
和 GB2312 一樣,GBK 也是雙字節編碼,為了向下兼容 GB2312, GBK 使用了 GB2312 沒有用到的編碼區域,總的編碼范圍是: 第一個字節 0x81–0xFE,第二個字節 0x40–0xFE, 具體的編碼范圍細分如下
上述表格中,紅色欄是 GBK 中包含的 GB2312 以及 ASICII 的編碼范圍,它們的編碼范圍保持不變
綠色欄的是 GBK 新增的編碼范圍
紫色欄是 用戶自定義編碼范圍
GB18030 編碼
與 GBK 不同的是,GB18030 是變長多字節字符集,每個字或字符可以由一個,兩個或四個字節組成,所以它的編碼空間是很大的,最多可以容納 161 萬個字符
由于需要兼容 GBK,四個字節的前兩個字節和 GBK 編碼保持一致,GB18030 具體的編碼范圍如下
GB18030 與 Unicode
GB18030 和 Unicode 相當于兩套單獨的編碼體系,它們都對世界上大部分字符進行編碼,賦予每個字符一個唯一的編號,只不過對于同一個字符,GB18030 和 Unicode 對應的編號是不一樣的, 比如:漢字 "中" 字的 GB18030 編碼是 0xD6D0, 對應的 Unicode 碼元是 0x4E2D, 從這一點上可以認為 GB18030 是一種 Unicode 的轉換格式
注意:要表達 Unicode 的編碼格式才真正算得上 Unicode 轉換格式,所以嚴格意義上說 GB18030 并不是真正的 Unicode 轉換格式
GB18030 既是字符集又是編碼格式,也即字符在字符集中的編號以及存儲是進行編碼用的編號是完全相同的,而 Unicode 僅僅是字符集,它只規定了字符的唯一編號,它的存儲是用其他的編碼格式的,比如 UTF8、UTF16 等等
既然 GB18030 和 Unicode 都能表示世界上大部分字符,為什么要弄兩套字符集呢,一套的話不更有利于信息的傳播嗎?
1、在 Unicode 出現之前,沒有統一的字符編碼,每個操作系統上都有自己的一套編碼標準,像早期的 window 上需要安裝字符集,才能支持中文,這里的字符集就是微軟自定的標準,換個其他系統就會失效
2、對于大部分中文字符來說,采用 GB18030 編碼的話,只需兩個字節,如果采用 UTF8 編碼,就需要三個字節, 所以用 GB18030 存儲和傳輸更節省空間
ASICII、GB2312、GBK、GB18030 以及 UTF8 的關系
它們的關系如下圖
由上圖可知,GB2312、GBK、GB18030 以及 UTF8 共同點是都兼容 ASICII
全角和半角字符
使用輸入法輸入字符的時候,有全角和半角之分,對于同一個字符,全角和半角對應的碼點是不一樣的
下面列出了一些字符的全角和半角的外觀截圖
半角是 ASICII 碼中的字符,對應的編碼范圍是 0x00 - 0x7F,每個字符占一個字節
全角是 GB2312 中的字符,每個字符占用兩個字節 ,其編碼范圍和半角字符范圍是沒有重疊的
對于漢字來說,是沒有全角和半角之分的
比如:上圖中 @ 符號,全角的編碼是 0xA3C0,占兩個字節, 半角的編碼是 0x40,占一個字節
通過內碼輸入漢字的方法
有時需要輸入一些特殊的字符,比如 帶圓圈的數字字符 ①,一般需要借助輸入法的小鍵盤來輸入
這里介紹一種使用字符內碼來快速輸入的方法: 按住 Alt 鍵不放,輸入字符內碼的十進制,輸入完后松開 Alt 鍵
例如,輸入帶圓圈的數字 ② 的步驟
1、查找帶圓圈數字 2 的字符的編碼 0xA2DA,十進制是 41690
2、按住 Alt 鍵不放,輸入 41690,松開 Alt 鍵
3、輸入完畢,這時就會出現字符 ②
一般 Linux的 SSH 連接工具 或 windows 上的記事本,都支持內碼輸入



































