GBK和UTF-8的粗暴判断
来源:互联网 发布:茶叶淘宝网 编辑:程序博客网 时间:2024/05/08 05:38
最近遇到一些url中携带没有encode掉的汉字,并且这样的url有的是utf-8编码,有的又是gbk编码。最终这些url被记录下来的时候,必然就有一类url是乱码了。有人说,汉语博大精深,可恰恰也是这些博大精深的东西时不时的让我们伤透脑筋。我认为这种url编码的情况,最专业的手法应该是url上有一个参数用来说明编码。现在既然没有人告诉我这个url是什么编码,那么我也得尽力判断,然后转换编码。
识别url的编码有个难点是其中的非ascii字符数量太少,容易误判。比如:我遇到的url中的非ascii字符一般就是搜索关键字。不过,简单的一面是url中的非ascii字符一般都是汉字,基本不会有特殊字符,西方字符等。因此,就将目标锁定在汉字的检测上,这基本足以满足需求,至少可以将这类乱码情况降低不少。
utf-8为一种变长编码字符集,也就是说一个字符可能由1个字节、2个字节、3个字节、4个字节,最多6个字节来表示。每种字节长度的编码模式如下:
有了上表中的变长编码模式,再结合云风总结的博客 (http://blog.codingnow.com/2010/06/detect_utf-8_gbk.html),基本可以得出如下的一个结论:
url中的非ascii字符只是汉字,那么遇到非ascii字符,就按utf-8的3字节编码规则去识别,匹配上,就认为是一个utf-8的字符,当url中所有的非ascii都能够和utf-8的3字节编码模式匹配时,就可以认为此编码是utf-8。那么,就可以将这个url转换到gbk了。这种判定方法显然是简单粗暴的,但应该可以解决绝大多数的情况。
云风博文中提到只要连续汉字数量不是3的倍数,就一定不会将gbk误认为UTF-8。这是因为gbk采用双字节对汉字进行编码,为了和单字节的ascii编码区分开,因此最高位一定是1, 除此没有规律可循了。也就是说GBK的汉字编码模式是:1xxxxxxx xxxxxxxx。现在假设我们的搜索关键字是3个汉字,这个3个汉字的gbk编码后的二进制大概长如下样子:
汉字1汉字2汉字31110xxxx 10xxxxxx10xxxxxx 1110xxxx10xxxxxx 10xxxxxx根据上表可以清楚的看到,3个汉字gbk编码后,按UTF-8 3字节编码模式可能被误判为两个汉字,红色和蓝色分别组成了新的汉字。不过,仔细想想3个汉字同时要符合这样的一个模式,概率应该是挺低的。从学术的角度来说,这个方法确实太简单粗暴了,但从工业生产的角度来看,只要能够很好的解决实际问题的方法就是好方法。最近刚好有测试系统在跑,把这个加入进去看看,实际效果究竟如何,能不能处理掉99%的情况。
还有一种方法应该更加的准确——假设url是gbk,那么首先将其转换到utf-8,然后在转换回GBK,最后逐字和原始url对比字节,看是否相同。这种方法就是要倒腾两次,作为需要处理海量url的服务器,性能上需要考虑。
附上代码(欢迎指正):
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stdint.h>#include <sys/types.h>#include <unistd.h>#include <fcntl.h>#define YES 0#define NO -1#define ASCII__MASK 0x80#define CHINESE_MASK1 0xF0#define CHINESE_MASK2 0xC0#define CHINESE_MASK3 0xC0#define ASCII_VALUE 0x00#define CHINESE_VALUE1 0xE0#define CHINESE_VALUE2 0x80#define CHINESE_VALUE3 0x80int check_utf8_chinese(u_char *data, size_t len){ u_char ch; size_t i, count, fail; enum { chinese1 = 0, chinese2, chinese3 } state; state = chinese1; count = 0; fail = 0; for (i = 0; i < len; i++) { ch = *(data + i); if (ch <= 127) { continue; } switch (state) { case chinese1: if (!((ch & CHINESE_MASK1) ^ CHINESE_VALUE1)) { state = chinese2; } else { fail++; } break; case chinese2: if (!((ch & CHINESE_MASK2) ^ CHINESE_VALUE2)) { state = chinese3; } else { state = chinese1; fail++; } break; case chinese3: if (!((ch & CHINESE_MASK3) ^ CHINESE_VALUE3)) { count++; } else { fail++; } state = chinese1; } } return fail != 0 ? NO : YES;}int main(int argc, char **argv){ int fd, n, ret; u_char buffer[1024]; fd = open(argv[1], O_RDONLY); if (fd < 0) { perror("open"); } n = read(fd, buffer, 1024); if (n < 0) { perror("read"); } ret = check_utf8_chinese(buffer, n); printf("%s\n", (ret == NO ? "gbk" : "utf-8")); return 0;}
- GBK和UTF-8的粗暴判断
- php如何判断 gbk 和utf-8
- GBK和UTF-8
- GBK和UTF-8
- gbk和utf-8
- GBK和UTF-8
- UTF-8和GBK
- GBK和UTF-8的区别
- UTF—8和GBK的区别
- GB2312,GBK和UTF-8的区别
- GBK和UTF-8的区别
- GBK和UTF-8的区分
- unicode 的utf-8 和GBK
- 浅谈UTF-8和GBK的区别
- utf-8 和gbk编码的区别
- 常见UTF-8和GBK的区别
- 关于GBK和UTF-8的编码
- UTF-8 和 GBK 编码的区别
- Android 自定义字体
- aspectj's load-time instrumentation
- 想来武汉工作么?---软件人 武汉求职、工作、生活体验报告(1)
- 转 写给Ruby新人的公开信 (我的Ruby学习经历)
- zz:make smdk2410_config命令详细解析
- GBK和UTF-8的粗暴判断
- 一个数组算法题,利用递归-回溯求解
- 电话窃听和拦截应用
- android.os包中一些类的使用
- ipad开发开发之区别于iphone
- GlusterFS资源收集
- 走迷宫——其实我发错了
- cbrgen和setdest数据流生成
- 了解函数