UTF-8和中文字符编码(GB2312、GBK、GIB5、GB18030)的识别
来源:互联网 发布:阿里云重新安装系统 编辑:程序博客网 时间:2024/05/29 01:55
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编码格式
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)。
GBKGBK编码是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、识别编码
实现原理:判断网页文本中符合utf-8规则的字数和不符合utf-8规则的字数
如果符合的字数超过90%,则判断为utf-8编码
其次应该是gb2312编码的判断,由于gb2312相对gbk和big5的编码范围要小,所以
在gb2312和gbk和big5之间,应该首先判断该网页文本是否是gb2312
函数实现:
实现原理:统计符合gb2312编码特征的字数和不符合gb2312编码特征的字数
如果符合的字数超过90%,则判断该网页文本为gb2312
再者应该判断big5编码,原因是因为gbk的范围要比big5的范围广
函数实现
实现原理同gb2312
最后是gbk的判断
函数实现
实现原理同gb2312和big5
3、各代码之间的相互转换
在linux下可以利用iconv实现转换,参考
http://blog.chinaunix.net/uid-29594401-id-4257317.html
2、识别编码
点击(此处)折叠或打开
- //judge the byte whether begin with binary 10
- int Encoder::is_utf8_special_byte(unsigned char c)
- {
- unsigned special_byte = 0X02; //binary 00000010
- if (c >> 6 == special_byte) {
- return 1;
- } else {
- return 0;
- }
- }
- int Encoder::is_utf8_code(const string& str)
- {
- unsigned one_byte = 0X00; //binary 00000000
- unsigned two_byte = 0X06; //binary 00000110
- unsigned three_byte = 0X0E; //binary 00001110
- unsigned four_byte = 0X1E; //binary 00011110
- unsigned five_byte = 0X3E; //binary 00111110
- unsigned six_byte = 0X7E; //binary 01111110
-
- int utf8_yes = 0;
- int utf8_no = 0;
-
- unsigned char k = 0;
- unsigned char m = 0;
- unsigned char n = 0;
- unsigned char p = 0;
- unsigned char q = 0;
-
- unsigned char c = 0;
- for (uint i=0; i<str.size();) {
- c = (unsigned char)str[i];
- if (c>>7 == one_byte) {
- i++;
- continue;
- } else if (c>>5 == two_byte) {
- k = (unsigned char)str[i+1];
- if ( is_utf8_special_byte(k) ) {
- utf8_yes++;
- i += 2;
- continue;
- }
- } else if (c>>4 == three_byte) {
- m = (unsigned char)str[i+1];
- n = (unsigned char)str[i+2];
- if ( is_utf8_special_byte(m)
- && is_utf8_special_byte(n) ) {
- utf8_yes++;
- i += 3;
- continue;
- }
- } else if (c>>3 == four_byte) {
- k = (unsigned char)str[i+1];
- m = (unsigned char)str[i+2];
- n = (unsigned char)str[i+3];
- if ( is_utf8_special_byte(k)
- && is_utf8_special_byte(m)
- && is_utf8_special_byte(n) ) {
- utf8_yes++;
- i += 4;
- continue;
- }
- } else if (c>>2 == five_byte) {
- unsigned char k = (unsigned char)str[i+1];
- unsigned char m = (unsigned char)str[i+2];
- unsigned char n = (unsigned char)str[i+3];
- unsigned char p = (unsigned char)str[i+4];
- if ( is_utf8_special_byte(k)
- && is_utf8_special_byte(m)
- && is_utf8_special_byte(n)
- && is_utf8_special_byte(p) ) {
- utf8_yes++;
- i += 5;
- continue;
- }
- } else if (c>>1 == six_byte) {
- k = (unsigned char)str[i+1];
- m = (unsigned char)str[i+2];
- n = (unsigned char)str[i+3];
- p = (unsigned char)str[i+4];
- q = (unsigned char)str[i+5];
- if ( is_utf8_special_byte(k)
- && is_utf8_special_byte(m)
- && is_utf8_special_byte(n)
- && is_utf8_special_byte(p)
- && is_utf8_special_byte(q) ) {
- utf8_yes++;
- i += 6;
- continue;
- }
- }
- utf8_no++;
- i++;
- }
- printf("%d %d\n", utf8_yes, utf8_no);
- int ret = (100*utf8_yes)/(utf8_yes + utf8_no);
- if (ret > 90) {
- return 1;
- } else {
- return 0;
- }
- }
实现原理:判断网页文本中符合utf-8规则的字数和不符合utf-8规则的字数
如果符合的字数超过90%,则判断为utf-8编码
其次应该是gb2312编码的判断,由于gb2312相对gbk和big5的编码范围要小,所以
在gb2312和gbk和big5之间,应该首先判断该网页文本是否是gb2312
函数实现:
点击(此处)折叠或打开
- int Encoder::is_gb2312_code(const string& str)
- {
- unsigned one_byte = 0X00; //binary 00000000
- int gb2312_yes = 0;
- int gb2312_no = 0;
- unsigned char k = 0;
- unsigned char c = 0;
- for (uint i=0; i<str.size();) {
- c = (unsigned char)str[i];
- if (c>>7 == one_byte) {
- i++;
- continue;
- } else if (c >= 0XA1 && c <= 0XF7) {
- k = (unsigned char)str[i+1];
- if (k >= 0XA1 && k <= 0XFE) {
- gb2312_yes++;
- i += 2;
- continue;
- }
- }
-
- gb2312_no++;
- i += 2;
- }
- printf("%d %d\n", gb2312_yes, gb2312_no);
- int ret = (100*gb2312_yes)/(gb2312_yes+gb2312_no);
- if (ret > 90) {
- return 1;
- } else {
- return 0;
- }
- }
实现原理:统计符合gb2312编码特征的字数和不符合gb2312编码特征的字数
如果符合的字数超过90%,则判断该网页文本为gb2312
再者应该判断big5编码,原因是因为gbk的范围要比big5的范围广
函数实现
点击(此处)折叠或打开
- int Encoder::is_big5_code(const string& str)
- {
- unsigned one_byte = 0X00; //binary 00000000
- int big5_yes = 0;
- int big5_no = 0;
- unsigned char k = 0;
- unsigned char c = 0;
- for (uint i=0; i<str.size();) {
- c = (unsigned char)str[i];
- if (c>>7 == one_byte) {
- i++;
- continue;
- } else if (c >= 0XA1 && c <= 0XF9) {
- k = (unsigned char)str[i+1];
- if ( k >= 0X40 && k <= 0X7E
- || k >= 0XA1 && k <= 0XFE) {
- big5_yes++;
- i += 2;
- continue;
- }
- }
-
- big5_no++;
- i += 2;
- }
- printf("%d %d\n", big5_yes, big5_no);
- int ret = (100*big5_yes)/(big5_yes+big5_no);
- if (ret > 90) {
- return 1;
- } else {
- return 0;
- }
- }
实现原理同gb2312
最后是gbk的判断
函数实现
点击(此处)折叠或打开
- int Encoder::is_gbk_code(const string& str)
- {
- unsigned one_byte = 0X00; //binary 00000000
- int gbk_yes = 0;
- int gbk_no = 0;
- unsigned char k = 0;
- unsigned char c = 0;
- for (uint i=0; i<str.size();) {
- c = (unsigned char)str[i];
- if (c>>7 == one_byte) {
- i++;
- continue;
- } else if (c >= 0X81 && c <= 0XFE) {
- k = (unsigned char)str[i+1];
- if (k >= 0X40 && k <= 0XFE) {
- gbk_yes++;
- i += 2;
- continue;
- }
- }
-
- gbk_no++;
- i += 2;
- }
- printf("%d %d\n", gbk_yes, gbk_no);
- int ret = (100*gbk_yes)/(gbk_yes+gbk_no);
- if (ret > 90) {
- return 1;
- } else {
- return 0;
- }
- }
实现原理同gb2312和big5
3、各代码之间的相互转换
在linux下可以利用iconv实现转换,参考
http://blog.chinaunix.net/uid-29594401-id-4257317.html
0 0
- UTF-8和中文字符编码(GB2312、GBK、GIB5、GB18030)的识别
- 字符编码就是那点事 (ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- ANSI、GBK、GB2312、UTF-8、GB18030和、UNICODE编码解读
- UTF-8、GB2312、GB18030、GBK和BIG5等字符集编码范围的具体说明
- UTF-8、GB2312、GB18030、GBK和BIG5等字符集编码范围的具体说明
- UTF-8、GB2312、GB18030、GBK和BIG5等字符集编码范围的具体说明
- UTF-8、GB2312、GB18030、GBK和BIG5等字符集编码范围的具体说明
- UTF-8、GB2312、GB18030、GBK和BIG5等字符集编码范围的具体说明
- 网页编码就是那点事( ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE) .
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- 编码格式简介(ANSI、GBK、GB2312、UTF-8、GB18030和 UNICODE)
- sql server 获取动态sql输出结果
- 程序员如何做到年薪超过60万?
- IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇) -- 保存link
- Java学习笔记(82)-----------阻塞队列
- 随笔笔记二——SpringMVC操作json数据
- UTF-8和中文字符编码(GB2312、GBK、GIB5、GB18030)的识别
- iOS类别(Category)与扩展(Extension)
- How does a relational database work - Coding Geek
- 使用delphi+intraweb进行微信开发1--微信平台接入
- apache做双向认证反向代理
- Js效果网站
- “#ifdef __cplusplus extern "C" { #endif”的定义
- 基于易班API的Java开发入门教程
- Java学习笔记(83)----------继承详解