UTF-8和中文字符编码(GB2312、GBK、GIB5、GB18030)的识别

本文详细介绍了ASCII、UTF-8、GB2312、GBK、GB18030和Big5等多种字符编码的特点与区别,并提供了编码识别算法的实现原理。此外,还涉及到了不同编码之间的转换方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、编码方式介绍
了解一种 字符集编码主要是要了解该编码的编码范围,编码对应的字符集(都包含哪些字符),和其他字符集编码之间的关系等。
ASCII
ASCII码是7位编码,编码范围是0x00-0x7F。ASCII 字符集包括英文字母、阿拉伯数字和标点符号等 字符。其中0x00-0x1F和0x7F共33个 控制字符[1]
只支持ASCII码的系统会忽略每个 字节的最高位,只认为低7位是有效位。HZ 字符编码就是早期为了在只支持7位ASCII系统中传输中文而设计的编码。早期很多 邮件系统也只支持 ASCII编码,为了传输中文邮件必须使用BASE64或者其他编码方式。
utf-8
utf-8编码的判断格式如下:
1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
这是标准的utf-8编码格式
GB2312
GB2312是基于区位码设计的,区位码把 编码表分为94个区,每个区对应94个位,每个字符的区号和位号组合起来就是该汉字的区位码。区位码一般 用10进制数来表示,如1601就表示16区1位,对应的字符是“啊”。在区位码的区号和位号上分别加上0xA0就得到了GB2312编码。
区位码中01-09区是符号、数字区 16-87区是汉字区,10-15和88-94是未定义的空白区。它将收录的汉字分成两级:第一级是 常用汉字 计3755个,置于16-55区,按 汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。一级汉 字是按照拼音排序的,这个就可以得到某个拼音在一级汉字区位中的范围,很多根据汉字可以得到拼音的程序就是根据这个原理编写的。
GB2312 字符集中除常用 简体汉字字符外还包括希腊字母、日文平假名及片假名字母、俄语 西里尔字母等字符,未收录 繁体中文汉字和一些生僻字。可以用繁体汉字测试某些系统是不是只支持GB2312编码。
GB2312的编码范围是0xA1A1-0xFEFE,去掉未定义的区域之后可以理解为实际编码范围是0xA1A1-0xF7FE(注意:实际编码值是前面的区、位值 + A0)。
GBK
GBK编码是GB2312编码的超集,向下完全兼容GB2312,同时GBK收录了Unicode 基本多文种平面中的所有CJK汉字。同 GB2312一样,GBK也支持希腊字母、日文假名字母、俄语字母等 字符,但不支持韩语中的表音字符(非汉字字符)。GBK还收录了GB2312不包含的 汉字部首符号、竖排标点符号等字符。
GBK的整体编码范围是为0x8140-0xFEFE,不包括低 字节 是0×7F的组合。高 字节 范围是0×81-0xFE,低字节范围是0x40-7E和0x80-0xFE。
字节 是0x40-0x7E的GBK 字符 有一定特殊性,因为这些字符占用了ASCII码的位置,这样会给一些系统带来麻烦。
有些系统中用0x40-0x7E中的 字符(如“|”)做特殊符号,在定位这些符号时又没有判断这些符号是不是属于某个 GBK字符的低 字节,这样就会造成错误判断。在支持GB2312的环境下就不存在这个问题。需要注意的是支持GBK的环境中小于0x80的某个 字节未必就 是ASCII符号;另外就是最好选用小于0×40的ASCII符号做一些特殊符号,这样就可以快速定位,且不用担心是某个汉字的另一半。Big5编码中也存在相应问题。
CP936和GBK的有些许差别,绝大多数情况下可以把CP936当作GBK的别名。
GB18030
GB18030编码向下兼容GBK和GB2312,兼容的含义是不仅 字符兼容,而且相同字符的编码也相同。GB18030收录了所有Unicode3.1中的字符,包括 中国少数民族字符,GBK不支持的韩文字符等等,也可以说是世界大多民族的文字符号都被收录在内。
GBK和GB2312都是双 字节 等宽编码,如果算上和ASCII兼容所支持的单 字节 ,也可以理解为是单字节和双字节混合的 变长编码 。GB18030编码是 变长编码 ,有单字节、双字节和四字节三种方式。
GB18030的单 字节 编码范围是0x00-0x7F,完全等同与ASCII;双字节编码的范围和GBK相同,高字节是0x81-0xFE,低字节 的编码范围是0x40-0x7E和0x80-FE;四字节编码中第一、三字节的编码范围是0x81-0xFE,二、四字节是0x30-0x39。
BIG5
Big5是双 字节编码,高字节编码范围是0x81-0xFE,低字节编码范围是0x40-0x7E和0xA1-0xFE。和GBK相比,少了低 字节是0x80-0xA0的组合。0x8140-0xA0FE是保留区域,用于用户造字区。
Big5收录的汉字只包括繁体汉字,不包括 简体汉字,一些生僻的汉字也没有收录。GBK收录的日文假名 字符、俄文字符Big5也没有收录。因为Big5当中收录的 字符有限,因此有很多在Big5基础上扩展的编码,如 倚天中文系统。Windows系统上使用的 代码页CP950也可以理解为是对Big5的扩展,在Big5的基础上增加了7个汉字和一些符号。Big5编码对应的 字符集是GBK字符集的子集,也就是说Big5收录的字符是GBK收录字符的一部分,但相同字符的编码不同。
因为Big5也占用了ASCII的编码空间(低 字节所使用的0x40-0x7E),所以Big5编码在一些环境下存在和GBK编码相同的问题,即低字节范围为0x40-0x7E的 字符有可能会被误处理,尤其是低字节是0x5C("/")和0x7C("|")的字符。可以参考GBK一节相应说明。
尽管有些区别,大多数情况下可以把CP950当作Big5的别名。

2、识别编码

点击(此处)折叠或打开

  1. //judge the byte whether begin with binary 10
  2. int Encoder::is_utf8_special_byte(unsigned char c)
  3. {
  4.     unsigned special_byte = 0X02; //binary 00000010 
  5.     if (>> 6 == special_byte) {
  6.         return 1;
  7.     } else {
  8.         return 0;
  9.     } 
  10. }

  11. int Encoder::is_utf8_code(const string& str)
  12. {
  13.     unsigned one_byte = 0X00; //binary 00000000
  14.     unsigned two_byte = 0X06; //binary 00000110
  15.     unsigned three_byte = 0X0E; //binary 00001110 
  16.     unsigned four_byte = 0X1E; //binary 00011110
  17.     unsigned five_byte = 0X3E; //binary 00111110
  18.     unsigned six_byte = 0X7E; //binary 01111110
  19.     
  20.     int utf8_yes = 0;
  21.     int utf8_no = 0;
  22.    
  23.     unsigned char k = 0;
  24.     unsigned char m = 0;
  25.     unsigned char n = 0;
  26.     unsigned char p = 0;
  27.     unsigned char q = 0;
  28.    
  29.     unsigned char c = 0; 
  30.     for (uint i=0; i<str.size();) {
  31.         c = (unsigned char)str[i]; 
  32.         if (c>>== one_byte) {
  33.             i++; 
  34.             continue;
  35.         } else if (c>>== two_byte) {
  36.             k = (unsigned char)str[i+1];
  37.             if ( is_utf8_special_byte(k) ) {
  38.                 utf8_yes++; 
  39.                 i += 2;
  40.                 continue;
  41.             }
  42.         } else if (c>>== three_byte) {
  43.             m = (unsigned char)str[i+1];
  44.             n = (unsigned char)str[i+2];
  45.             if ( is_utf8_special_byte(m)
  46.                     && is_utf8_special_byte(n) ) {
  47.                 utf8_yes++;
  48.                 i += 3;
  49.                 continue;
  50.             }
  51.         } else if (c>>== four_byte) {
  52.             k = (unsigned char)str[i+1];
  53.             m = (unsigned char)str[i+2];
  54.             n = (unsigned char)str[i+3];
  55.             if ( is_utf8_special_byte(k)
  56.                     && is_utf8_special_byte(m)
  57.                     && is_utf8_special_byte(n) ) {
  58.                 utf8_yes++;
  59.                 i += 4;
  60.                 continue;
  61.             }
  62.         } else if (c>>== five_byte) {
  63.             unsigned char k = (unsigned char)str[i+1];
  64.             unsigned char m = (unsigned char)str[i+2];
  65.             unsigned char n = (unsigned char)str[i+3];
  66.             unsigned char p = (unsigned char)str[i+4];
  67. if ( is_utf8_special_byte(k)
  68.                     && is_utf8_special_byte(m)
  69.                     && is_utf8_special_byte(n)
  70.                     && is_utf8_special_byte(p) ) {
  71.                 utf8_yes++;
  72.                 i += 5;
  73.                 continue;
  74.             }
  75.         } else if (c>>== six_byte) {
  76.             k = (unsigned char)str[i+1];
  77.             m = (unsigned char)str[i+2];
  78.             n = (unsigned char)str[i+3];
  79.             p = (unsigned char)str[i+4];
  80.             q = (unsigned char)str[i+5];
  81.             if ( is_utf8_special_byte(k)
  82.                     && is_utf8_special_byte(m)
  83.                     && is_utf8_special_byte(n)
  84.                     && is_utf8_special_byte(p)
  85.                     && is_utf8_special_byte(q) ) {
  86.                 utf8_yes++;
  87.                 i += 6;
  88.                 continue;
  89.             }
  90.         } 

  91.         utf8_no++;
  92.         i++; 
  93.     } 

  94.     printf("%d %d\n", utf8_yes, utf8_no);
  95.     int ret = (100*utf8_yes)/(utf8_yes + utf8_no);
  96.     if (ret > 90) {
  97.         return 1; 
  98.     } else {
  99.         return 0;
  100.     }
  101. }


实现原理:判断网页文本中符合utf-8规则的字数和不符合utf-8规则的字数
如果符合的字数超过90%,则判断为utf-8编码

其次应该是gb2312编码的判断,由于gb2312相对gbk和big5的编码范围要小,所以
在gb2312和gbk和big5之间,应该首先判断该网页文本是否是gb2312
函数实现:

点击(此处)折叠或打开

  1. int Encoder::is_gb2312_code(const string& str)
  2. {
  3.     unsigned one_byte = 0X00; //binary 00000000

  4.     int gb2312_yes = 0;
  5.     int gb2312_no = 0;

  6.     unsigned char k = 0;

  7.     unsigned char c = 0;
  8.     for (uint i=0; i<str.size();) {
  9.         c = (unsigned char)str[i];
  10.         if (c>>== one_byte) {
  11.             i++;
  12.             continue;
  13.         } else if (>= 0XA1 && c <= 0XF7) {
  14.             k = (unsigned char)str[i+1];
  15.             if (>= 0XA1 && k <= 0XFE) {
  16.                 gb2312_yes++;
  17.                 i += 2;
  18.                 continue;
  19.             } 
  20.         }
  21.        
  22.         gb2312_no++;
  23.         i += 2; 
  24.     }

  25.     printf("%d %d\n", gb2312_yes, gb2312_no);
  26.     int ret = (100*gb2312_yes)/(gb2312_yes+gb2312_no);
  27.     if (ret > 90) { 
  28.         return 1;
  29.     } else {
  30.         return 0;
  31. } 
  32. }


实现原理:统计符合gb2312编码特征的字数和不符合gb2312编码特征的字数
如果符合的字数超过90%,则判断该网页文本为gb2312

再者应该判断big5编码,原因是因为gbk的范围要比big5的范围广
函数实现

点击(此处)折叠或打开

  1. int Encoder::is_big5_code(const string& str)
  2. {
  3.     unsigned one_byte = 0X00; //binary 00000000

  4.     int big5_yes = 0;
  5.     int big5_no = 0;

  6.     unsigned char k = 0; 

  7.     unsigned char c = 0; 
  8.     for (uint i=0; i<str.size();) {
  9.         c = (unsigned char)str[i];
  10.         if (c>>== one_byte) {
  11.             i++;
  12.             continue;
  13.         } else if (>= 0XA1 && c <= 0XF9) {
  14.             k = (unsigned char)str[i+1];
  15.             if ( k >= 0X40 && k <= 0X7E
  16.                     || k >= 0XA1 && k <= 0XFE) {
  17.                 big5_yes++;
  18.                 i += 2;
  19.                 continue;
  20.             } 
  21.         }
  22.        
  23.         big5_no++;
  24.         i += 2;
  25.     }

  26.     printf("%d %d\n", big5_yes, big5_no);
  27.     int ret = (100*big5_yes)/(big5_yes+big5_no);
  28.     if (ret > 90) {
  29.         return 1;
  30.     } else {
  31.         return 0;
  32.     } 
  33. }


实现原理同gb2312

最后是gbk的判断
函数实现

点击(此处)折叠或打开

  1. int Encoder::is_gbk_code(const string& str)
  2. {
  3.     unsigned one_byte = 0X00; //binary 00000000

  4.     int gbk_yes = 0;
  5.     int gbk_no = 0;

  6.     unsigned char k = 0;

  7.     unsigned char c = 0;
  8.     for (uint i=0; i<str.size();) {
  9.         c = (unsigned char)str[i];
  10.         if (c>>== one_byte) {
  11.             i++;
  12.             continue;
  13.         } else if (>= 0X81 && c <= 0XFE) {
  14.             k = (unsigned char)str[i+1];
  15.             if (>= 0X40 && k <= 0XFE) {
  16.                 gbk_yes++;
  17.                 i += 2;
  18.                 continue;
  19.             } 
  20.         }
  21.        
  22.         gbk_no++;
  23.         i += 2; 
  24.     }

  25.     printf("%d %d\n", gbk_yes, gbk_no);
  26.     int ret = (100*gbk_yes)/(gbk_yes+gbk_no);
  27.     if (ret > 90) { 
  28.         return 1;
  29.     } else {
  30.         return 0;
  31.     } 
  32. }


实现原理同gb2312和big5
3、各代码之间的相互转换
在linux下可以利用iconv实现转换,参考
http://blog.chinaunix.net/uid-29594401-id-4257317.html
<think>好的,我现在需要解答用户关于GBGiBGb的区别及含义的问题。首先,我要确保自己正确理解这些单位之间的不同,并准确传达给用户。用户可能对这些数据单位的使用场景转换关系有疑问,因此需要详细解释每个单位的定义、用途以及它们之间的转换方法。 首先,GB(Gigabyte)GiBGibibyte)都是数据存储单位,但它们的基数不同。GB使用的是十进制,而GiB使用二进制。这一点需要明确区分,因为很多人可能混淆这两者。根据引用[1],KiB、MiB、GiB是二进制单位,而KB、MB、GB是十进制单位。因此,在转换时,1GB等于10^9字节,而1GiB等于2^30字节,即1,073,741,824字节。这导致同样的数值,GiB实际上比GB稍大,因此在存储设备标称容量时可能会有差异,比如厂商标注的1TB硬盘在操作系统中显示为约931GiB,这是因为厂商使用十进制而系统使用二进制计算。 接下来是Gb(Gigabit),这通常用于数据传输速率,如网络带宽。Gb中的“b”是小写,代表bit(位),而GB中的“B”是大写,代表Byte(字节)。1字节等于8位,因此1Gb等于1,000,000,000位,而1GB等于8,000,000,000位。用户需要注意区分大小写,避免混淆。 转换关系方面,需要分别处理十进制二进制单位之间的转换,以及位字节之间的转换。例如,将GB转换为GiB时,需要使用不同的基数。同时,GbGB的转换需要除以8,因为1字节等于8位。这些转换步骤需要清晰列出,避免用户混淆。 此外,根据引用[2],访问存储设备涉及复杂的操作,如校验元数据处理,这可能影响实际可用空间。因此,存储设备的标称容量实际可用容量之间的差异不仅仅是单位转换的问题,还涉及其他技术因素。这一点也需要提及,以全面解答用户的疑问。 在组织回答结构时,应该分点解释每个单位的定义、用途转换关系,使用示例帮助用户理解。同时,引用相关的参考资料来支持解释,确保信息的准确性。最后,生成相关问题,帮助用户进一步探索该主题,例如不同单位的应用场景、如何计算实际存储空间等。 需要检查是否有遗漏的信息点,例如是否解释了每个单位的全称、应用领域,以及转换公式的正确性。确保使用正确的大小写单位符号,避免技术错误。同时,保持语言简洁明了,适合不同层次的读者理解。</think>### GBGiBGb的区别及含义 #### 1. **单位定义与用途** - **GB(Gigabyte,吉字节)** 采用十进制(10进制),1 GB = $10^9$ 字节 = 1,000,000,000 字节。常用于存储设备容量标注(如硬盘、U盘)文件大小描述[^1]。 - **GiBGibibyte,吉二进制字节)** 采用二进制(2进制),1 GiB = $2^{30}$ 字节 = 1,073,741,824 字节。主要用于操作系统软件中对存储空间的精确计算。 - **Gb(Gigabit,吉比特)** 表示数据传输速率单位,1 Gb = $10^9$ 比特 = 1,000,000,000 比特。常见于网络带宽(如“千兆宽带”)接口速率(如USB 3.0)的标注。注意区分大小写:`b` 代表比特(bit),`B` 代表字节(Byte)。 #### 2. **关键区别** - **进制差异** - GB(十进制)与 GiB(二进制)的转换关系: $$1 \, \text{GiB} \approx 1.0735 \, \text{GB}$$ 例如,标称 1 TB(1000 GB)的硬盘实际显示约 931 GiB- Gb(比特)与 GB(字节)的转换关系: $$1 \, \text{GB} = 8 \, \text{Gb}$$ 例如,下载速度为 1 Gbps(1 Gb/s)时,实际文件传输速率为 125 MB/s。 - **应用场景** - **存储容量**:GB/GiB用于描述静态数据大小(如文件、硬盘)。 - **传输速率**:Gb用于动态数据传输(如网络带宽、接口速度)。 #### 3. **实际示例** - **存储设备标称与系统显示差异** 厂商标注的 256 GB SSD 在操作系统中显示为约 238 GiB,这是因为: $$256 \times 10^9 \, \text{字节} \div 2^{30} \approx 238 \, \text{GiB}$$ 这种差异源于进制标准不同,并非“缩水”。 - **网络带宽与下载速度** 若宽带为 1 Gbps(1 Gb/s),理论最大下载速度为: $$1 \, \text{Gb/s} \div 8 = 125 \, \text{MB/s}$$ 实际速度可能因协议开销(如TCP/IP头部)进一步降低[^2]。 #### 4. **总结对比表** | 单位 | 进制 | 用途 | 换算关系 | |------|-------|----------------|-------------------------| | GB | 10进制| 存储容量 | 1 GB = $10^9$ 字节 | | GiB | 2进制 | 存储精确计算 | 1 GiB = $2^{30}$ 字节 | | Gb | 10进制| 数据传输速率 | 1 Gb = $10^9$ 比特 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值