刨根究底字符編碼之六——簡體漢字編碼中區位碼、國標碼、內碼、外碼、字形碼的區別及關系


簡體漢字編碼中區位碼、國標碼、內碼、外碼、字形碼的區別及關系

 


 
 
GB2312、GBK、GB18030等GB類漢字編碼方案的具體實現方式是怎樣的?區位碼是什么?國標碼是什么?內碼、外碼、字形碼又是什么意思?它們是如何轉換的,又為什么要這樣轉換?

下面以GB2312為例來加以說明(由於GBK、GB18030是以GB2312為基礎擴展而來,因此編碼實現方式與GB2312一樣)。

 

一、區位碼

1.

整個GB2312字符集分成94個區,每區有94個位,每個區位上只有一個字符,即每區含有94個漢字或符號,用所在的區和位來對字符進行編碼(實際上就是字符編號、碼點編號),因此稱為區位碼(或許叫“區位號”更為恰當)。

換言之,GB2312將包括漢字在內的所有字符編入一個94 * 94的二維表,行就是“區”、列就是“位”,每個字符由區、位唯一定位,其對應的區、位編號合並就是區位碼。比如“萬”字在45區82位,所以“萬”字的區位碼是:45 82(注意,GB類漢字編碼為雙字節編碼,因此,45相當於高位字節,82相當於低位字節)。

2.

GB2312字符集中:

1)01~09區(682個):特殊符號、數字、英文字符、制表符等,包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西里爾字母等在內的682個全角字符;

2)10~15區:空區,留待擴展;

3)16~55區(3755個):常用漢字(也稱一級漢字),按拼音排序;

4)56~87區(3008個):非常用漢字(也稱二級漢字),按部首/筆畫排序;

5)88~94區:空區,留待擴展。

 

二、國標碼(交換碼)

1.

為了避開ASCII字符中的不可顯示字符0000 0000 ~ 0001 1111(十六進制為0 ~ 1F,十進制為0 ~ 31)及空格字符0010 0000(十六進制為20,十進制為32)(至於為什么要避開、又為什么只避開ASCII中0~32的不可顯示字符和空格字符,后文有解釋),國標碼(又稱為交換碼)規定表示漢字的范圍為(0010 0001,0010 0001) ~ (0111 1110,0111 1110),十六進制為(21,21) ~ (7E,7E),十進制為(33,33) ~ (126,126)(注意,GB類漢字編碼為雙字節編碼)。

因此,必須將“區碼”和“位碼”分別加上32(十六進制為20H,后綴H表示十六進制),作為國標碼。也就是說,國標碼相當於將區位碼向后偏移了32,以避免與ASCII字符中0~32的不可顯示字符和空格字符相沖突。

2.

注意,國標碼中是分別將區位碼中的“區”和“位”各自加上32(20H)的,因為GB2312是DBCS雙字節字符集,國標碼屬於雙字節碼,“區”和“位”各作為一個單獨的字節。

這樣我們可以算出“萬”字的國標碼十進制為:(45+32,82+32) = (77,114),十六進制為:(4D,72H),二進制為:(0100 1101,0111 0010)。

(笨笨阿林原創文章,轉載請注明出處)

 

三、內碼(機內碼)

1.

不過國標碼還不能直接在計算機上使用,因為這樣還是會和早已通用的ASCII碼沖突(導致亂碼)。

比如,“萬”字國標碼中的高位字節77與ASCII的“M”沖突,低位字節114與ASCII的“r”沖突。因此,為避免與ASCII碼沖突,規定國標碼中的每個字節的最高位都從0換成1,即相當於每個字節都再加上128(十六進制為80,即80H;二進制為1000 0000),從而得到國標碼的“機內碼”表示,簡稱“內碼”。

2.

由於ASCII碼只用了一個字節中的低7位,所以,這個首位(最高位)上的“1”就可以作為識別漢字編碼的標志,計算機在處理到首位是“1”的編碼時就把它理解為漢字,在處理到首位是“0”的編碼時就把它理解為ASCII字符。

比如:

77 + 128 = 205(二進制為1100 1101,十六進制為CD)

114+ 128 = 242(二進制為1111 0010,十六進制為F2)

3.

我們可以來檢驗一下。打開記事本輸入“萬”字,編碼選擇為ANSI(Windows記事本中的ANSI編碼對於簡體漢字而言就是GB類編碼,詳見后文解釋),保存,如下圖所示。

 

然后用二進制編輯器(比如UltraEdit)打開剛才保存的文件,切換到十六進制模式,會看到:CD F2,這就是“萬”字的內碼,如下圖所示。


  4.

總結一下:

從區位碼(國家標准定義) ---> 區碼和位碼分別+32(即+20H)得到國標碼 ---> 再分+128(即+80H)得到機內碼(與ACSII碼不再沖突)。

因此,區位碼的區和位分別+160(即+A0H,32+128=160)可直接得到內碼。用十六進制表示就是:

區位碼(區碼,位碼) + (20H,20H) + (80H,80H) =區位碼(區碼,位碼) + (A0H,A0H) = 內碼(高字節,低字節)。

 

 

四、為什么要加上20H和80H

1.

區位碼、國標碼、內碼的轉換非常簡單,但是令人迷惑的是為什么要這么轉換?

首先,需要注意到一點,GB2312雖說是對中文編碼,但是里面也有對26個英文字母和一些特殊符號的編碼,按理說這些和ASCII重合的字符(33~127)應該無需再重新編碼,直接沿用ASCII中的不就行了?

2.

原來,當時在制定GB2312時,決定對ASCII中的可打印字符,也就是英文字母、數字和符號部分(33~126,127為不可打印的DEL)重新編入GB2312中,以兩個字節表示,稱之為全角字符(全角字符在屏幕上的顯示寬度為ASCII字符的兩倍,后來也因此而將對應的ASCII字符稱之為半角字符)。

而對於ASCII中前32個不可顯示也不可打印的控制字符(ASCII碼為0~31),以及第33個可顯示但不可打印的空格字符(ASCII碼為32)等共33個不可打印字符的編碼則直接沿用,不再重新編碼。

3.

因為要保留這33個不可打印字符,就不能直接采用區位碼作為計算機直接處理的機內碼,需要將區位碼向后偏移32以避開沖突(為什么是偏移32,而不是偏移33?因為區位碼中的區碼和位碼都是從1開始計數的,不像ASCII碼是從0開始計數的)。

十進制數字32的十六進制表示就是20(為區別於十進制,記作20H),這也就是區位碼要加上20H(區碼和位碼各自加上20H)才能得到國標碼的原因。

(笨笨阿林原創文章,轉載請注明出處)

3.

很顯然,如果直接采用國標碼作為計算機直接處理的機內碼的話,還將會產生另一個弊端,即用ASCII碼編碼的英文字符在GB2312編碼環境中無法打開,一打開就會亂碼。

因為國標碼雖然相較於區位碼避開了ASCII碼中0~32的前33個不可打印字符,但並沒有避開ASCII碼中的英文字母、數字和符號(33~126,共94個字符,127為不可打印的DEL)等可打印字符。也就是說,國標碼並不是完全兼容ASCII碼的。

4.

為了解決這個弊端,考慮到ASCII碼只使用了一個字節中的低7位,最高位(即首位)為0,於是決定將國標碼每個字節的最高位設為1(國標碼的兩個字節中的最高位都恆為0,即國標碼中的每個字節實際上也只用了一個字節中的低7位),這就是GB2312的機內碼(即內碼),簡稱GB2312碼。

這樣一來就徹底區分開了ASCII碼和GB2312碼。這也是為什么國標碼還要加上(80H,80H)才能得到機內碼的原因。

5.

看到這里,有人或許又要問了:如果僅僅是為了避免與ASCII編碼相沖突,為什么最初不直接將區位碼的區碼和位碼的最高位從0改為1(相當於各自直接加上128),這樣不就無需經過國標碼多此一舉的中間轉換了嗎?而且還無需后移32,也就不用浪費這部分編碼空間。

對此本人也很困惑,在網上搜了很久也沒找到答案,因此具體原因不得而知。或許是一開始考慮不周?或許為了未來擴展所需而預留一部分空間?又或許是有其他不得已的原因?有知道的朋友還望能指點迷津。


GB2312區位碼、國標碼、內碼對照表(其中漢字內碼B0A1~F7FE,共6763個)
 

五、外碼(輸入碼、輸入法編碼)

1.

外碼也叫輸入碼、輸入法編碼,是用來將漢字輸入到計算機中的一組鍵盤符號,是作為漢字輸入用的編碼。

英文字母只有26個,可以把所有的字符都放到鍵盤上,而使用這種辦法把所有的漢字都放到鍵盤上,是不可能的。所以漢字系統需要有自己的輸入碼體系,使漢字與鍵盤能建立對應關系。

2.

目前常用的外碼分為以下幾類:

1)數字編碼,比如區位碼;

2)拼音編碼,比如全拼、雙拼、自然碼等;

3)字形編碼,比如五筆、表形碼、鄭碼等。

 

六、字形碼(字型碼、字模碼、輸出碼)

1.

字形碼,又稱為字型碼、字模碼、輸出碼,屬於點陣代碼的一種。

為了將漢字在顯示器或打印機上輸出,把漢字按圖形符號設計成點陣圖,就得到了相應的點陣代碼(字形碼)。

也就是用0、1表示漢字的字形,將漢字放入n行*n列的正方形(點陣)內,該正方形共有n^2個小方格,每個小方格用一位二進制表示,凡是筆划經過的方格值為1,未經過的值為0。

2.

顯示一個漢字一般采用16×16點陣或24×24點陣或48×48點陣。已知漢字點陣的大小,可以計算出存儲一個漢字所需占用的字節空間。

比如,用16×16點陣表示一個漢字,就是將每個漢字用16行,每行16個點表示,一個點需要1位二進制代碼,16個點需用16位二進制代碼(即2個字節),共16行,所以需要16行×2字節/行=32字節,即16×16點陣表示一個漢字,字形碼需用32字節。

因此,字節數=點陣行數×(點陣列數/8)。

3.

顯然,字形碼所表示的字符,相對於抽象字符表ACR里的“抽象”字符,可稱之為“具體”字符,因為具有了“具體”的外形。

4.

為了將漢字的字形顯示輸出或打印輸出,漢字信息處理系統還需要配有漢字字形庫,也稱字模庫,簡稱字庫,它集中了漢字的字形信息。

字庫按輸出方式可分為顯示字庫和打印字庫。用於顯示輸出的字庫叫顯示字庫,工作時需調入內存。用於打印輸出的字庫叫打印字庫,工作時無需調入內存。

字庫按存儲方式也可分為軟字庫和硬字庫。軟字庫以文件的形式存放在硬盤上,現多用這種方式。硬字庫則將字庫固化在一個單獨的存儲芯片中,再和其它必要的器件組成接口卡,插接在計算機上,通常稱為漢卡。這種方式現已淘汰。

 

七、小結


 
可以這樣理解,為在計算機內表示漢字而采取統一的編碼方式所形成的漢字編碼叫內碼。為方便漢字輸入而形成的漢字編碼為外碼,也叫輸入碼。為顯示輸出和打印輸出漢字而形成的漢字編碼為字形碼,也稱為字模碼、輸出碼。

計算機通過鍵盤輸入的外碼(重碼時還需附加選擇編號)對應於漢字內碼,將漢字外碼轉換(即映射)為漢字內碼,以實現輸入漢字的目的;通過漢字內碼在字模庫(即字庫)中找出漢字的字形碼,將漢字內碼轉換(即映射)為漢字字形碼,以實現顯示輸出和打印輸出漢字的目的。


事實上,英文字符的輸入、處理和顯示過程大致上也差不多,只不過英文字符不需要輸入碼(即外碼),直接在鍵盤上輸入對應的英文字母即可。

(笨笨阿林原創文章,轉載請注明出處)

 

【預告:下一篇將重點剖析非常容易令人困惑的所謂ANSI編碼與代碼頁(Code Page),敬請關注!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM