C語言漢字編碼 梳理


一、關於漢字編碼和字庫

根據漢字使用頻率,正常使用的漢字約15000個,根據頻率可分為高頻字、常用字、次常用字、罕見字和死字。我國1981年發布《通訊用漢字字符集(基本集)及其交換碼標准》GB2312-80方案,將高頻字、常用字、次常用字編成漢字基本字符集共6763個。又在該字符集中使用頻率,分成3755個按拼音排序的一級漢字和3008個按部首排序的二級漢字,另外編碼收錄了包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西里爾字母在內的682個全角字符。

二、漢字編碼

區位碼——分區表示

 

國家標准的漢字字符集GB2312-80,即國標,對收錄字符進行分區管理:將字庫分成94個區,每個區有94個漢字(按位編排),每一個漢字在字庫中有確定的區和位編號,即所謂的兩個字節表示的區位碼,區位碼第一個字節表示區號,第二個字節表示位號,由區位碼即可獲取漢字在字庫中的地址。其中:

  • 01-09區收錄除漢字外的682個字符
  • 10-15區為空白區,沒有使用
  • 16-55區收錄3755個一級漢字,按拼音排序
  • 56-87區收錄3008個二級漢字,按部首/筆畫排序
  • 88-94區為空白區,沒有使用
  • 例:“啊”是GB2312中的第一個漢字,區位碼是1601

每個漢字在字庫中以點陣字模形式存儲,一般為16×16點陣形式。每個點用一個二進制位表示,存1的點,可以在屏幕上顯示一個亮點,存0的點則不顯示,存字的16*16點陣信息在顯示器上顯示,即可出現對應漢字。

國標碼

GB2312規定對收錄的每個字符采用兩個字節表示,第一個字節為“高字節”,對應94個區,第二個字節為“低字節”,對應94個位,所以其編碼范圍是:0101-9494。GB2312為中文編碼,但是也會用到英文字母等字符,為了兼容,需避開ASCII中不可顯示字符0000 0000-0001 1111(十六進制0-1F,十進制0-31)及空格字符0010 0000 ,國標碼規定漢字的表示范圍為0010 0001,0010 0001-0111 1110,0111,1110(十六進制為2121-7E7E,十進制為3333-126-126),即分別將區碼和位碼加上20H(十六進制數,代表十進制中的32,H為十六進制數的后綴:Hexadecimal)。即國標碼就是區位碼向后偏移32,以避免和ASCII碼中0-32的不可顯示字符和空格字符相沖突的結果。

內碼/機內碼

國標碼雖然向后偏移20H,但是還是會和ASCII碼中的除控制字符外的其他字符沖突,導致亂碼,為解決這個問題,規定把國標碼中的每個字節的最高位從0換成1,相當於每個字節再加上128(十六進制80H,二進制1000 0000)即得到所謂的機內碼,即內碼,ASCII碼只用了一個字節中的低7位,最高位為0,所以最高位為1就可以作為區別漢字編碼和ASCII碼的標志。

總結一下:編碼范圍

綜上所述,內碼才是字符用GB2312編碼后在計算機中存儲的形式。

GB2312規定對收錄的每個字符采用兩個字節表示,第一個字節為“高字節”,對應94個區,第二個字節為“低字節”,對應94個位,所以其編碼范圍是:0101-9494.區號和位號分別加上0xA0就是GB2312編碼。例:最后一個碼位是9494,區號和位號分別轉成16進制是5E5E,0x5E+0xA0=0xFE,即該碼位的GB2312編碼是FEFE。

編碼范圍:

  • GB2312內碼范圍:A1A1-FEFE
  • 其中漢字的編碼范圍是B0A1-F7FE
  • 第一字節0xB0-OxF7,對應區號16-87
  • 第二個字節0xA1-0xFE,對應位號01-94

解釋:一個字節對應8位,8位的數可以表示的范圍為0-256,但是這里的范圍是1-94,規定,當區號和位號分別先后加上0x20、0x80,即總共加上0xA0后就是GB2312對應的機內碼。對於區號和位號的組合體,0101-9494,加上一個0xA0十六進制數變成GB2312編碼:高字節的最小數1轉換成:1+0xA0=0x01+0xA0=0xA1,高字節最大數94轉換成:94+0xA0=0x5E+0xA0=0xFE,即可求是GB2312編碼范圍:A1A1=FEFE。

區位碼+32(0x20)=國標碼
國標碼+128(0x80)=機內碼
->區位碼+160(0xA0)=機內碼

 

三、20H和80H

為什么加上20H:

不可/可打印字符:ASCII中的可打印字符即英文字母/數字/和符號部分(33-126,127為不可打印的DEL),其余的為控制字符等不可打印字符

全角字符/半角字符:制定GB2312時,決定把ASCII中的可打印字符重新編入GB2312中,以兩個字節表示,稱為全角字符,全角字符在屏幕上顯示的空度為ASCII字符的兩倍,對應的ASCII字符也因此被稱為半角字符;

同時,對於前32個控制字符(ASCII碼為0-31)以及第33個可顯示但是不可打印的空格字符(ASCII碼32)等共33個不可打印字符的ASCII編碼直接沿用,不再重新編碼,所以不能采用區碼直接作為計算機處理的機內碼,需要向后偏移32以避開和前33個字符的沖突。因為區碼中的區碼和位碼都是從1開始計數,ASCII碼是從0開始計數,所以向后偏移32而不是33.這也就是最終版本的國標碼

為什么加上80H:

直接采用國標碼作為計算機直接處理的機內碼時,因為沒有避開ASCII碼中的英文字母、數字和其他符號(33-126,共94個字符,127為不可打印的DEL),若用ASCII碼編碼的英文字符在GB2312編碼的環境中則同樣會發生亂碼,即國標碼並沒有完全兼容ASCII碼。考慮到ASCII碼只使用了一個字節中的低7位,最高位為0,國標碼兩個字節中的最高位原本都恆為0,即國標碼中的每個字節實際上也只用了一個字節中的低7位。於是決定將國標碼的每個字節的最高位設為1,即形成了GB2312的機內碼,即內碼,簡稱GB2312碼。即國標碼要再加上80H才變成機內碼。

四、外碼/輸入碼/輸入法編碼

是用來將漢字輸入到計算機中的一組鍵盤符號,是作為漢字輸入用的編碼。是漢字系統的輸入體系,使漢字與鍵盤建立對應關系。主要有以下幾類

  • 數字編碼:如區位碼
  • 拼音編碼,如全拼/雙拼/自然拼
  • 字形編碼:如五筆/表形碼/鄭碼等

字形碼/字型碼/輸出碼

把漢字按圖形設計成點陣圖,就得到了相應的點陣代碼,即字形碼。就是用0、1表示漢字的字形,將漢字放入n行n列共n2正方形點陣內,凡是筆畫經過的方格值為1,其余為0.

顯示一個漢字一般用16*16,24*24或48*48點陣。存儲一個漢字所需占用的點陣字節空間:字節數=點陣行數*(點陣列數/8)。如用16*16點陣表示一個漢字,即將每個漢字用16行每行16個點表示,一個點需要1位二進制代碼,共需16行*2字節/行=32個字節。

為了將漢字的字形顯示或者打印出,漢字信息處理系統還配有漢字字形庫,也稱字模庫/字庫。按輸出方式可分為顯示字庫和打印字庫。顯示字庫用於顯示輸出,工作時需調入內存,打印字庫用於打印輸出無需調入內存。

漢字字模在字庫中存放的位置根據漢字的區位碼來確定,在支持漢字輸入的系統中,鍵盤鍵入的漢字內碼即在程序中存在,將其轉換為區位碼,再從字庫中找到對應的漢字字模,用有關的操作和循環語句,對每個字節的每一位進行判斷,像過濾一樣,某位為1則按設置的顏色,用graphics.h中顯示像素點的函數putpixel()在屏幕的相應位置畫點,為0則不畫,這樣就可以按預設的顏色在相應位置顯示出漢字。

 

例:

①內碼到區位碼的轉換
若漢字內碼為十六進制數h2h1l2l1,則區號qh 相位號wh 分別為:
qh= h2h1-0xa0;
wh= l2l1-0xa0;
若用十進制表示內碼為dld2,則
qh=dl-l60;
wh=d2-160;
即區位碼qw 為:
qw=100*(d1-160)十(d2-160);
反過來,若已經知道了區位碼qw。則也可求得區號和位號:
qh=qw/100;
wh=qw-100*qh;
②因而該漢字在漢字庫中離起點的偏移位置(以字節為單位),可計算為:
offset=(94*(qh-1)+(wh-1))* 32;
③這樣即可以找尋到文件的偏移量,讀出一個char bytes[32]數組。這樣bytes 數組中則
存了要顯示漢字的16×16 點陣字模,然后將字模按行掃描的辦法,通過循環用putpixel()函
數在屏幕設定位置顯示出象點,因而組合成一個顯示的漢字。

 

參考資料:

徹底解決亂碼問題

國標2312編碼

漢字機內碼/國標碼和區位碼的區別


免責聲明!

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



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