菜鸟有感:编码啊,编码!最终解决方案,不要再纠结!
2012-02-20 16:58
417 查看
关于idhttp取网页源码编码问题,在这里记录最后一次的解决方法,不想再纠结下去,再也伤不起了。(本文内容均在d2010,indy10.55的环境下产生及结束)。
网上只要搜索关于idhttp取网页乱码,idyttp编码问题的文章有一大堆,试了无数,都不满意,最后再这里记录一下个人解决方法。
在IDE中写如下代码,str:=http.get(xxxxx);然后Ctrl跟踪get,会在源码中得到如下一行,也是最关键的一行:
很明显,idhttp想给我们做点好事,直接返回解码后(能正常阅读、没有乱码)的内容,问题来了,当Response.CharSet有值时,返回的内容是完全正确的,当Response.CharSet没有值时,返回的结果值得商榷了。所以就有了网上常有人问的“为什么在UTF-8的情况下,返回内容是正常的,但是GBK的就不行了?”,经我测试,当网页是UTF-8时,Response.CharSet='utf-8',当网页是GBK时,Response.CharSet就不一定是GBK,很多时候都是空的,这时候,在使用上面的函数时,CharSet默认为西欧(可能吧)编码,得到的内容比UTF-8编码后的结果更难看懂。所以,我们要做的,就是给CharSet一个可用的、正确的值。
如果得到一个可用的、正确的CharSet值呢?首先,idhttp.Response.CharSet这个是首选的,如果这个值为空呢,就需要在返回的HTML中找了,如:
在上面代码中醒目的部分,charset=utf-8,我们要的就是这个,这部分是英文,所以不管什么编码,都能正常得到这部分内容,需要做的就是用正则把charset=后面的内容取出,再判断具体的编码,一般只需要考虑两种情况:utf-8和gbk,实现代码如下:
我承认,我欺骗了你,因为在上面的代码中,我没有给CharSet找一个正确的值,而是用到了IdGlobal, IdGlobalProtocols中的两个函数,直接返回一个理想的内容,就像你看到的,首先,需要一个http:IDHTTP和isutf8:boolean,然后直接调用 str:=GetMethod(xxxxxx)就可以得到内容了。
通过如上方法,能解决80%的网页编码问题,为什么不是100%呢,因为还有一部分的网页,通过idhttp.get,你会发现Response.CharSet='',并且在HTML中没有设置编码的meta标签,如果这种情况,请不要纠结,略过它吧。。。。
注明:本文只适合菜鸟阅读,也欢迎高手拍砖。
网上只要搜索关于idhttp取网页乱码,idyttp编码问题的文章有一大堆,试了无数,都不满意,最后再这里记录一下个人解决方法。
在IDE中写如下代码,str:=http.get(xxxxx);然后Ctrl跟踪get,会在源码中得到如下一行,也是最关键的一行:
Result := ReadStringAsCharset(LResponse, Response.CharSet);
很明显,idhttp想给我们做点好事,直接返回解码后(能正常阅读、没有乱码)的内容,问题来了,当Response.CharSet有值时,返回的内容是完全正确的,当Response.CharSet没有值时,返回的结果值得商榷了。所以就有了网上常有人问的“为什么在UTF-8的情况下,返回内容是正常的,但是GBK的就不行了?”,经我测试,当网页是UTF-8时,Response.CharSet='utf-8',当网页是GBK时,Response.CharSet就不一定是GBK,很多时候都是空的,这时候,在使用上面的函数时,CharSet默认为西欧(可能吧)编码,得到的内容比UTF-8编码后的结果更难看懂。所以,我们要做的,就是给CharSet一个可用的、正确的值。
如果得到一个可用的、正确的CharSet值呢?首先,idhttp.Response.CharSet这个是首选的,如果这个值为空呢,就需要在返回的HTML中找了,如:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>执行 Application.Terminate 后, OnDestroy 中的代码还会执行 - 万一 - 博客园</title> <link type="text/css" rel="stylesheet" href="http://www.cnblogs.com/css/common.css"/>
在上面代码中醒目的部分,charset=utf-8,我们要的就是这个,这部分是英文,所以不管什么编码,都能正常得到这部分内容,需要做的就是用正则把charset=后面的内容取出,再判断具体的编码,一般只需要考虑两种情况:utf-8和gbk,实现代码如下:
function Txxxxxx.getMethod(AURL: string): string; var LResponse: TMemoryStream; LEncoding:TIdTextEncoding; per:TPerlRegEx; begin LResponse := TMemoryStream.Create; try try http.Get(AURL, LResponse); finally http.Disconnect; end; LResponse.Position := 0; if http.Response.CharSet<>'' then begin LEncoding := CharsetToEncoding(http.Response.CharSet); if AnsiSameText(http.Response.CharSet,'utf-8') then isutf8:=true else isutf8:=False; end else begin LEncoding := TEncoding.Default; Result := ReadStringFromStream(LResponse, -1, LEncoding); per:=TPerlRegEx.Create(nil); per.Options:=[preCaseLess]; per.Subject:=Result; per.RegEx:='<meta[\S\s]*?charset=(.*)>'; if per.Match then begin if AnsiContainsText(per.MatchedExpression,'utf-8') then begin isutf8:=true; LEncoding := CharsetToEncoding('utf-8'); end else begin isutf8:=False; LEncoding := CharsetToEncoding('gbk'); end; end; FreeAndNil(per); end; LResponse.Position := 0; Result := ReadStringFromStream(LResponse, -1, LEncoding); finally FreeAndNil(LResponse); end; end;
我承认,我欺骗了你,因为在上面的代码中,我没有给CharSet找一个正确的值,而是用到了IdGlobal, IdGlobalProtocols中的两个函数,直接返回一个理想的内容,就像你看到的,首先,需要一个http:IDHTTP和isutf8:boolean,然后直接调用 str:=GetMethod(xxxxxx)就可以得到内容了。
通过如上方法,能解决80%的网页编码问题,为什么不是100%呢,因为还有一部分的网页,通过idhttp.get,你会发现Response.CharSet='',并且在HTML中没有设置编码的meta标签,如果这种情况,请不要纠结,略过它吧。。。。
注明:本文只适合菜鸟阅读,也欢迎高手拍砖。
相关文章推荐
- 对于ASP编码问题的深入研究与最终解决方案
- 对于ASP编码问题的深入研究与最终解决方案
- 对于ASP编码问题的深入研究与最终解决方案
- 对于ASP编码问题的深入研究与最终解决方案
- Ajax缓存和编码问题的最终解决方案
- 对于ASP编码问题的深入研究与最终解决方案
- 【备忘】java读写文件编码最终解决方案
- 错误的结果2......VC/bin/cl.exe返回的最终解决方案
- oracle在32位的Linux环境下SGA如何突破2GB内存限制的最终解决方案
- jsp中文问题最终解决方案
- url 编码 js url传参中文乱码解决方案
- Java路径问题最终解决方案—可定位所有资源的相对路径寻址
- 【Python】Python2.7 编码问题:'ascii' codec can't encode characters in position 的解决方案
- JSP中IE直接关闭后如何去清SESSION的最终解决方案
- IE不支持getElementsByClassName最终完美解决方案
- 关于“因为数据库正在使用,所以无法获得对数据库的独占访问权”的最终解决方案
- Reflector的FileDisassembler插件输出结果为乱码的解决方案。(增加编码选择)
- 关于“因为数据库正在使用,所以无法获得对数据库的独占访问权”的最终解决方案
- java执行jar出现编码问题的解决方案,Could not decode a text frame as UTF-8
- 关于“因为数据库正在使用,所以无法获得对数据库的独占访问权”的最终解决方案