做一个站内搜索遇到一个问题:
网站全站使用的是UTF-8编码,所以get请求的URL也用UTF-8编码,服务器端用UTF-8解码。这种情况下,用户直接在表单里输入提交过来搜索,是没有问题的。但如果用户直接在浏览器地址栏里把关键词给改了,提交过来,或者从浏览器地址栏的下拉提示列表里点击过来,URL编码就不确定了。这个和操作系统语言以及浏览器相关。
ie默认情况下,对在地址栏里输入的URL路径里的中文是用utf-8编码的,但对get参数不会自动编码,会直接把原始字符串发过去。
其他浏览器都会对地址栏里输入的get参数进行编码,编码方式和操作系统环境语言相关。
研究了一下几个大的搜索引擎是怎么处理这个问题的。
1.百度,搜狗等国内搜索引擎
这些搜索引擎的默认编码都是gb2312的,所以一般用户不会遇到这种问题。但我的系统是linux,系统编码是zh_CN.UTF-8的,就会遇到这种问题。
如百度:
gb2312编码:
http://www.baidu.com/s?wd=%D6%D0%B9%FA
utf-8编码
http://www.baidu.com/s?wd=%E4%B8%AD%E5%9B%BD
所以国内的搜索引擎基本没处理这个问题。应该认为这样的用户比较少,可以不予考虑吧。
2. google.com
google.com默认编码是utf-8,也只接受utf-8编码的地址,否则会出现乱码。google.com面对的是全球用户,不会专门为了中国用户而做特殊处理,可以理解。
gb2312
http://www.google.com/search?q=%D6%D0%B9%FA
utf-8
http://www.google.com/search?q=%E4%B8%AD%E5%9B%BD
3.google.cn
google.cn的默认编码也是utf-8。但它针对的是中文用户。而中文用户的大多数操作系统是中文的windows,浏览器的默认编码也一般是gb2312,所以这个问题必须考虑。google.cn能同时兼容两种编码。
gb2312:
http://www.google.cn/search?q=%D6%D0%B9%FA
utf-8:
http://www.google.cn/search?q=%E4%B8%AD%E5%9B%BD
google.cn是怎么做到的?
有人说数query里的%号,utf-8的一个汉字是3个字节,所以有三个%,而gb2312的编码的汉字是2个字节,2个%号。但遇到2和3的倍数呢?比方6个字节,是当3个gb2312的汉字处理呢还是2个utf-8的汉字处理呢?
于是在网上找了一下UTF-8的编码规则:
UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的用x表示的二进制位,全部用这个符号的unicode码填充。
下表总结了编码规则,字母x表示可用编码的位。
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
汉字的unicode符号范围是4e00-9fff(其中9FA6~9FFF还是空码),正好在第三行的范围内,也就是说每个汉字在UTF-8中都会转换为3个字节。其中第一个字节在11100000(0xE0)-11101111(0xEF)范围内,后两个字节在10000000(0x80)-10111111(0xBF)范围内。
于是办法产生了:
private static boolean isUTF8Query(String q)
throws UnsupportedEncodingException {
byte[] bytes = q.getBytes("ISO-8859-1");
for (int i = 0; i < bytes.length; i++) {
//java 中的byte是有符号的,大于127的都为负数。先转换为int型正数再比较。
int first = 0x100 + bytes[i];
//寻找查询关键词中的第一个中文字符的第一个字节
if (first < 0xE0 || first > 0xEF) {
continue;
}
if (i + 2 < bytes.length) {
int second = 0x100 + bytes[i + 1];
int third = 0x100 + bytes[i + 2];
if (second >= 0x80 && second <= 0xBF && third >= 0x80
&& third <= 0xBF) {
return true;
}
}
}
return false;
}
使用:
String q= request.getParameter("q");
q = isUTF8Query(q)?new String(q.getBytes("ISO-8859-1"),"UTF-8"):new String(q.getBytes("ISO-8859-1"),"GBK");
也有人用搜索queryString里的 %E 的个数的方式做这件事情。不过那样一方面不太准确,另一方面ie不会自动把用户在地址栏输入的get查询中的中文URLEncode,那样的情况下服务器端获取的queryString里没有%,
服务器端的问题:
用这种方式的时候,服务器端不能让服务器自动解码。如果是tocmat的话,在connector上不能设置URIEncoding="UTF-8",否则tomcat用utf-8解码后,再还原为原始字符串的字节比较麻烦。
如果是其他语言,比方php或者python,也不能让apache自动解码。
演示地址:
gb2312编码:
http://so.1ting.com/song.do?q=%C1%F5%B5%C2%BB%AA
utf-8编码:
http://so.1ting.com/song.do?q=%E5%88%98%E5%BE%B7%E5%8D%8E
地址栏里直接输入中文也可以。
分享到:
相关推荐
URL编码转换器,写搜索引擎时遇害到URI编码问题,顺手写了这个小软件~
pen.py的search子命令提供了Google Hacking的功能,目前支持以下搜索引擎: baidu bing google 例如: pen.py search "inurl:viewthread.php" -s 10 -o tmp.txt # --unique设定域名唯一,相同域名只记录一个...
4.3.7 定义搜索引擎搜索方式 4.4 用于http消息报头的元数据(属性http-equiv) 4.4.1 设置网页内容类型和字符集 4.4.2 设置网页所使用的语言 4.4.3 设置网页定时跳转 4.4.4 设置网页禁用缓存 4.4.5 设置网页到期 4.4.6...
decodeURIComponent 方法 返回一个已编码的通用资源标识符 (URI) 组件的解码版。 递减运算符(--) 将变量减一。 delete 运算符 删除对象的属性,或删除数组中的一个元素。 description 属性 返回或设置关于指定...
decodeURIComponent 方法 返回一个已编码的通用资源标识符 (URI) 组件的解码版。 递减运算符(--) 将变量减一。 delete 运算符 删除对象的属性,或删除数组中的一个元素。 description 属性 返回或设置关于指定...
decodeURIComponent 方法 返回一个已编码的通用资源标识符 (URI) 组件的解码版。 递减运算符(--) 将变量减一。 delete 运算符 删除对象的属性,或删除数组中的一个元素。 description 属性 返回或设置关于指定...
23.5 使用操作键和应用程序特有的搜索数据 23.5.1 在Android搜索中使用操作键 23.5.2 使用应用程序特定的搜索上下文 23.6 资源 23.7 对平板电脑的意义 23.8 小结 第24章 文本到语音转换 24.1 ...
23.5 使用操作键和应用程序特有的搜索数据 23.5.1 在Android搜索中使用操作键 23.5.2 使用应用程序特定的搜索上下文 23.6 资源 23.7 对平板电脑的意义 23.8 小结 第24章 文本到语音转换 24.1 ...
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。 10、&和&&的区别。 &是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and)。 11、HashMap...
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。 13、&和&&的区别。 &是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑与(and)。 14、...
• 集成的浏览器 基于开源的 WebKit 引擎 • 优化的图形库 包括定制的 2D 图形库, 3D 图形库基于 OpenGL ES 1.0 (硬件加速可选) • SQLite SQLite SQLite SQLite 用作结构化的数据存储 • 多媒体支持 包括常见的...
JAVA模版引擎Freemarker常用标签(一) 1. if指令 这是一个典型的分支控制指令,该指令的作用完全类似于Java语言中的if,if指令的语法格式如下: <#if condition>... <#elseif condition>... <#elseif condition>......