欢迎您的访问
专注于分享最有价值的互联网技术干货

各种编码格式(GB2312,GBK,GB18030,UNICODE,UTF-8)之间的关系

几个T的资料等你来白嫖
双倍快乐

汉字常用编码格式

为了在屏幕上显示字符。需要下面几个步骤:

  1. 制作所有字符对应的字模。比如大写字母A长什么样。这个模样就是最终显示在屏幕上图形,即我们看到的字符A
  2. 为对所有的字符进行编码。比如大写字母A的编码为0x41.
  3. 由于字符的数量远大于一个字节,所以当字符编码进行存储、传输时,需要给它们指定格式。如怎样确定某个字符的编码是一字节还是多字节。如0xC0 0xEE代表一个字符的编码(0xC0EE)还是两个字符的编码(0xC0、0xEE)。

第1个步骤的工作也就是我们常见的制作字体,比如宋体楷体等。它只关心字符的长相。而第二、三个步骤有些是一起做的。如GB2312GB18030的编码方式。有些是分开的,如unicode编码指做了第而步骤,而将第三步骤交给了utf-8utf-16utf-32等。

计算机在屏幕上显示字符的流程是,加载存储好的文本,通过编码方式解析出字符编码,然后通过字符编码找到对应的字符字模,然后显示。由于计算机的发展是一步步迭代的,由于之前的编码方式不能满足后续的工作需求,所以出现了很多中的编码方式。如我们常见的GB2312utf-8等。下图是常用编码方式之间的关系图:

20210421122648416.jpg

GB18030、GBK、GB2312汉字编码格式

GB2312编码

GB2312编码是第一个汉字编码国家标准,由中国国家标准总局1980年发布,1981年5月1日开始使用。GB2312编码共收录汉字6763个,其中一级汉字3755个,二级汉字3008个。同时,GB2312编码收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个全角字符。。它使用2个字节编码,编码范围为A1A1~FEFE。其中首字节叫区,尾字节叫位。共A1~FE94个区,每个区包含A1~FE94个位。共94*94=8836个码位。

  1. 1~9区收录除汉字外的682个字符。
  2. 10-15区为空白区,没有使用。
  3. 16-55区收录3755个一级汉字,按拼音排序。
  4. 56-87区收录3008个二级汉字,按部首/笔画排序。
  5. 88-94区为空白区,没有使用。

GBK编码

GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。GBK中的K为汉语拼音的声母,即扩展的含义。英文全称Chinese Internal Code Specification。GBK编码标准兼容GB2312。GB2312基本满足了汉字的计算机处理需要,但对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致了后来GBK及GB18030汉字字符集的出现。GBK采用双字节表示,总体编码范围为8140-FEFE,首字节在81-FE之间,尾字节在40-FE之间,剔除xx7F一条线。总计23940个码位,共收入21886个汉字和图形符号.

GB18030编码

在2000年,GB18030取代GBK1.0,正式国家标准。它的主要特点是在GBK基础上增加了CJK统一汉字扩充A的汉字(GB18030-2000)。后又在此基础上增加了CJK统一汉字扩充B的汉字(GB18030-2005)。

GB18030编码格式有单字节、双字节、四字节三种方案。其中单、双字节的编码和GBK完全兼容。4字节的编码内容为CJK扩展A的6582个汉字。

unicode编码及格式

unicode官网:https://www.unicode.org

上面提到的GBxxx都是我们国家定义的标准,当然只针对我们公家的汉字以及ASCII等。而unicode的出现是为了解决全球的字符编码。以满足跨语言、跨平台进行文本转换、处理的要求。这样我们就可以在一篇文章中用n国语言来写我爱你了。

unicode与UCS-2、UCS-4

早期 Unicode 在编制通用字符集之时,ISO 组织也在做同样的事情,ISO 开展了 ISO/IEC 10646 项目,名字叫“ Universal Multiple-Octet Coded Character Set”,中文译为“通用多八位编码字符集”,英文简称UCS。后来双方整合,到 Unicode 2.0 时,Unicode 编码和 UCS 编码都基本一致。
UCS-2 采用 16 位存储空间,两个字节编码每个字符,而 UCS-4 采用 4 个字节(实际上只用了 31 位,最高位必须为 0)编码。
UCS-4 根据最高位为 0 的最高字节分成27=128个组(group)。每个组再根据次高字节分为256个平面(plane)。每个平面根据第3个字节分为256行(rows),每行包含256个单元(cells)。当然同一行的单元只是最后一个字节不同,其余都相同。
0组的0号平面被称作Basic Multilingual Plane,即基本多文种平面,简写BMP。可知BMP区域内的字符只使用了两个字节,码位从 U+0000 至 U+FFFF。它实际上就是 UCS-2 的全部编码范围,后来因为码位不够用才扩展为 UCS-4。

17个平面中目前只用到0号、1号、2号和14号平面,其中汉字在0号平面和2号平面,其它文字在0号、1号和14号平面;
20210421122648769.jpg
具体的汉字Unicode编码范围见此链接:https://www.qqxiuzi.cn/zh/hanzi-unicode-bianma.php.

utf-8、utf-16、utf-32编码格式

要说unicode与utf-8、utf-16、utf-32之间的关系,我们须明确编码格式=编码+存储格式。其中编码对应文章开头提到的第二个步骤,存储格式对应第三个步骤。unicode只是编码,不涉及存储格式。而utf-x是基于unicode编码的编码格式。清楚这点,我们也就清楚了utf-8、utf-16、utf-32三者的关系。它们的都使用unicode编码,那肯定存储格式存在差异,因此起了三个名呗。说到这儿,会有一个疑问?那GB2312、GBK等的编码存储格式分别是什么了?其实,GB2312、GBK等是将编码存储格式整合到了一起。因为GB2312的编码是从A1A1~FEFE,它和ASCII(0x00~0x7F)在字节流上本身就不冲突。当文本中的字节小于0x80,他一定为ASCII码。而当文本中的字节大于0x80时,此字节加下一个字节共同表示一个汉字。而unicode编码就不同了,它的字符编码中的每个字节都可以小于0x80,那么它的这个字节代表ASCII呢还是和其他字节组合表示一个别的字符(如汉字)?没法确定,所以必须要有存储格式。下面将谈论它们的编码格式。

utf-8编码格式

utf-8官网:http://www.utf-8.com/

utf-8(Unicode Transformation Format 8-bit)是一种可变宽度的编码格式。用1~4个字节表示一个Unicode字符编码。它可以表示unicode字符集中的所有字符。
utf-8编码格式:

  1. 它是一个变长字节(1~4个字节)的编码方式。
  2. 对于一个字节的编码格式:字节bit[7:0]的bit[7]位必须为0,bit[6:0]这7个位用来编码,即二进制为0b0xxxxxxx
  3. 对于n(n>1)字节(2,3,4个字节)的编码格式:
    1. 用首字节的bit[7:8-n]位置1,bit[8-n-1]置位0表示字节位数。如首字节为0b110xxxxx表示二字节的编码格式。同理0b1110xxxx为三字节格式。剩下的
    2. 除首字节剩下的字节的bit[7:6]=0b10.其余位用于编码。
      如编码0b1110xxxx,0b10xxxxxx,0b10xxxxxx表示一个三字节的编码格式,其中x代表的是可编码的位置。可以计算出三字节编码格式共有2^24个编码位置。
      如表是1~4字节的具体编码格式表:
utf-8 n字节编码格式 编号范围
0b0xxxxxxx 0x00~0x7F
0b110xxxxx 0b10xxxxxx 0x80~0x7FF
0b1110xxxx 0b10xxxxxx 0b10xxxxxx 0x800~0xFFFF
0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx 0x10000~0x10FFFF

上面是存储格式,那如何将unicode字符编码填充到utf-8的格式里了?
unicode编码转化为utf-8编码的步骤如下:

  1. 首先找到unicode字符编码所在上表中的编号范围。如字符A的unicode编码为0x41,位于utf-8 1字节编码格式(0~127)的编号范围。
  2. 将unicode字符编码的二进制位从右到左填入上表中的x位(注意要去掉高位的0)。如字符A(0x41=0b01010001)去掉高位0则为0b1010001。将其填入0b0xxxxxxx后则为0b01010001.也就是utf-8字符A的编码值。
    再举个例子:汉字的unicode字符编码为0x90ED(0b10010000,11101101),由0x800 < 0x90ED < 0xFFFF得到它的编码格式为utf-8的3字节编码格式。然后将其二进制0b10010000,11101101填入0b1110xxxx 0b10xxxxxx 0b10xxxxxx后为0b11101001,10000011,10101101=0xE983AD.也就是utf-8字符的编码值。

有了utf-8与unicode之间的关系,就很容易写出转换程序。下面是c语言实现的utf-8编码转unicode编码

/* 
 * utf-8字符编码转化为unicode编码。(2字节模式)
 * pIn:要转换的字符串首地址
 * charsize:接收返回的utf8字符的字节数(1~3)
 * pOut:获取到的UCS2编码,pOut[0]为首字节。
 */
int Utf8ToUCS2(const char *pIn,char *charsize,char *pOut)
{


    uint8_t firstValue = *pIn;
    char *pUCS2 = pOut;

    if(firstValue < 0x80){

   //0~127 ASCII 1byte
        pUCS2[0] = 0;
        pUCS2[1] = *pIn;
        *charsize = 1;
    }
    else if( (firstValue & 0xE0) == 0xC0){

   //128~2047 2byte
        if( (pIn[1] & 0xC0) != 0x80){


            return -1;
        }
        pUCS2[0] = (pIn[0] & 0x1F) >> 2;
        pUCS2[1] = (pIn[0] << 6) + (pIn[1] & 0x3F);
        *charsize = 2;
    }
    else if( (firstValue & 0xF0) == 0xE0){

   //2048~65536 3byte
        if( (pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80){


            return -1;
        }
        pUCS2[0] = (pIn[0] << 4) + ((pIn[1] & 0x3F) >> 2);
        pUCS2[1] = (pIn[1] << 6) + (pIn[2] & 0x3F);
        *charsize = 3;
    }
    else {

   //>3byte不处理,汉字用不到4字节的编码
        *charsize = 0;
        return -1;
    }

    return 0;
}

汉字编码转换工具及编码表

1.千千秀字:https://www.qqxiuzi.cn/daohang.htm 这个网站上有编码之间的转换、编码值查询、汉字码值表等编码相关的工具。

赞(0) 打赏
版权归原创作者所有,任何形式转载请联系我们:大白菜博客 » 各种编码格式(GB2312,GBK,GB18030,UNICODE,UTF-8)之间的关系

评论 抢沙发

4 + 8 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏