且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

汉字编码(转载)

更新时间:2022-08-22 12:18:20

一、汉字编码的种类 

    汉字编码中现在主要用到的有三类,包括GBK,GB2312和Big5。 

    1、GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。我们平时说6768个汉字,实际上里边有5个编码为空白,所以总共有6763个汉字。 

       GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。GB2312中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制为160-254)。 

       GB2312将代码表分为94个区,对应第一字节(0xa1-0xfe);每个区94个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区(0xb0-0xf7),10-15区、88-94区是有待进一步标准化的空白区。 

    2、Big5又称大五码,主要为***与***使用,即是一个繁体字编码。每个汉字由两个字节构成,第一个字节的范围从0X81-0XFE(即129-255),共126种。第二个字节的范围不连续,分别为0X40-0X7E(即64-126),0XA1-0XFE(即161-254),共157种。 

    3、GBK是GB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相同。另外,GBK中还包含繁体字的编码,它与Big5编码之间的关系我还没有弄明白,?孟袷遣灰恢碌摹?GBK中每个汉字仍然包含两个字节,第一个字节的范围是0x81-0xFE(即129-254),第二个字节的范围是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字21003个。                           

                                   表1 汉字编码范围 

                    名称    第一字节              第二字节 
  
                    GB2312  0xB0-0xF7(176-247)    0xA0-0xFE(160-254) 
  
                    GBK     0x81-0xFE(129-254)    0x40-0xFE(64-254) 
  
                    Big5    0x81-0xFE(129-255)    0x40-0x7E(64-126) 

                                                  0xA1-0xFE(161-254) 
  

  

二、对汉字进行hash 

    为了处理汉字的方便,在查找汉字的时候,我们通常会用到hash的方法,那怎么来确定一个汉字位置呢?这就和每种编码的排列有关了,这里主要给出一种hash函数的策略。 

    对于GB2312编码,设输入的汉字为GBword,我们可以采用公式(C1-176)*94 + (C2-161)确定GBindex。其中,C1表示第一字节,C2表示第二字节。具体如下: 

    GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161; 

    之所以用unsigned char类型,是因为char是一个字节. 

    对于GBK编码,设输入的汉字为GBKword,则可以采用公式   index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128),其中ch1是第一字节,ch2是第二字节。 

    具体的, 

    GBKindex = ((unsigned char)GBKword[0] - 129) * 190 + ((unsigned char)GBKword[1] - 64) - (unsigned char)GBKword[1] / 128; 

三、怎样判断一个汉字的是什么编码 

    1、判断是否是GB2312 

    bool isGBCode(const string& strIn) 

    { 

        unsigned char ch1; 

        unsigned char ch2; 

        if (strIn.size() >= 2) 
        { 

            ch1 = (unsigned char)strIn.at(0); 

            ch2 = (unsigned char)strIn.at(1); 

            if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254) 

                return true; 

            else return false; 
        } 

        else return false; 

    } 

    2、判断是否是GBK编码 

    bool isGBKCode(const string& strIn) 

    { 

        unsigned char ch1; 

        unsigned char ch2; 

        if (strIn.size() >= 2) 

        { 

            ch1 = (unsigned char)strIn.at(0); 

            ch2 = (unsigned char)strIn.at(1); 

            if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254) 

                return true; 

            else return false; 

        } 

        else return false; 

    } 

    3、对于Big5 

        它的范围为:高字节从0xA0到0xFE,低字节从0x40到0x7E,和0xA1到0xFE两部分。判断一个汉字是否是BIG5编码,可以如上对字符的编码范围判断即可。如何定位呢?那么也想象所有编码排列为一个二维坐标,纵坐标是高字节,横坐标是低字节。这样一行上的汉字个数:(0x7E-0x40+1)+(0xFE-0xA1+1)=157。那么定位算法分两块,为:   

        if 0x40<=ch2<=0x7E: #is big5 char  

        index=((ch1-0xA1)*157+(ch2-0x40))*2  

        elif 0xA1<=ch2<=0xFE: #is big5 char  

        index=((ch1-0xA1)*157+(ch2-0xA1+63))*2  

四、如果判断一个字符是西文字符还是中文字符 

    大家知道西文字符主要是指ASCII码,它用一个字节表示。且这个字符转换成数字之后,该数字是大于0的,而汉字是两个字节的,第一个字节的转化为数字之后应该是小于0的,因此可以根据每个字节转化为数字之后是否小于0,判断它是否是汉字。 

    例如,设输入字为strin,则, 

    If (strin.at(0) < 0) 

        cout << "是汉字" << endl; 

     else 

        cout << "不是汉字" << endl; 

     补充: 

     1.汉字外部码 

     汉字外部码又称为汉字输入码,是指从键盘上输入汉字时采用的编码。汉字输入编码有很多种,目前广泛使用的输入码为: 

     ① 国标区位码 

     ② 以汉字读音为基础的拼音码,如全拼输入法、双拼输入法、词汇输入法、智能ABC输入法等; 

     ③ 以汉字字形为基础的拼形码,如五笔字型输入法; 

     不同的汉字输入方法有不同的外码,但内码只能有一个。好的输入方法应具备规则简单、操作方便、容易记忆、重码率低、速度快等特点。 

     2.汉字国标码 

     GB2312-80编码简称国标码。由于汉字数量大,无法用一个字节进行编码,因此使用两个字节对汉字进行编码。规定两个字节的最高位用来区分ASCII码。这样国标码用两个字节的低7位对汉字进行编码。 

     一个字节只能有128-34=94种状态用于汉字编码(34是指34种控制字符),两个字节可以表示94×94=8836种状态。在基本集中汉字是按规则排列成94行和94列的矩阵,形成汉字编码表,其行号称为区号,列号称为位号,第一个字节表示汉字在国标字符集中的区号,第二个字节表示汉字在国标字符集中的位号。每一个汉字在94×94的矩阵中都有一个固定的区号和位号。 

     例如:汉字“大”的区号为20,位号为83,即“大”的区位码为2083。 

     国标码是以十六进制数字编码,编码范围是从2121H(21H即为十进制的33)到7F7FH(7FH即为十进制的127)。 

     因此,国标码=区位码(用十六进制表示)+2020H。 

     3.汉字机内码 

     机内码是指一个汉字被计算机内部系统进行存储、处理和传输时而使用的编码。为了保证中西文兼容,同时又能区分ASCII码和汉字,因此,机内码就是将国标码的两个字节的最高位置为“1”。 

     所以,机内码=国标码+8080H=区位码(用十六进制表示)+A0A0H 。 

     4.汉字字形码 

     字形码又称汉字字模,用于汉字的输出。汉字的字形通常采用点阵的方式产生。汉字点阵有16×16点阵、32×32点阵、64×64点阵,点阵不同,汉字字形码的长度也不同。点阵数越大,字形质量越高,字形码占用的字节数越多。 

     如图1.1是“国”字24×24的点阵字形。深色小正方形可以表示一个二进制位的信息“1”,浅色小正方形表示二进制位的信息“0”。 

     汉字字形码又称为汉字输出码或汉字发生器的编码。 

     例:按32×32点阵存放两级汉字的汉字库,大约需要占用多少字节? 

     解:32×32×6763÷8=865664B≈845KB 

     大约需要845KB。