源码下载地址:http://download.youkuaiyun.com/source/414086
汉字编码是一项较为麻烦的事情,弄不好就会造出些谁都看不懂的乱码。比如我想做个针对汉字网站的爬虫系统,需要对非特定的页面进行数据解析处理,而此时我所访问的页面编码格式未知,如果不能正确处理页面编码,则很难获得我们理想中的数据。
通常这时候可能有几种选择:
一是根据response的ContentType获得,如果服务器支持的话此项中会返回charset数值,解析即可。但对不返回或者不支持的服务器则无能为力。
二是使用正则或自定义解析函数截取页面中‘charset=’后的数据,采取死钉战术,但万一采集的页面中没有此项或者此项有错,也就回天乏术。
三就是老老实实的解析全文,最后返回一个符合的编码格式。
此例中我演示了几种较常见编码的识别方法,通过统计编码为指定编码的或然率, 而后返回可能性最高的编码方式。在无法获得确切编码之时,这可说是一种唯一的选择。
这种识别方式主要是针对汉字编码而来,所以对应页面中的汉字数目越多,统计结果就越准确,反之则很难识别出正确结果。
Encoding.java
package
org.loon.test.encoding;


/** */
/**
* <p>
* Title: LoonFramework
* </p>
* <p>
* Description:编码基本类型集合
* </p>
* <p>
* Copyright: Copyright (c) 2008
* </p>
* <p>
* Company: LoonFramework
* </p>
* <p>
* License: http://www.apache.org/licenses/LICENSE-2.0
* </p>
*
* @author chenpeng
* @email:ceponline@yahoo.com.cn
* @version 0.1
*/

public
class
Encoding
...
{

// 支持的字符格式
public static int GB2312 = 0;

public static int GBK = 1;
public static int BIG5 = 2;

public static int UTF8 = 3;

public static int UNICODE = 4;

public static int EUC_KR = 5;

public static int SJIS = 6;

public static int EUC_JP = 7;

public static int ASCII = 8;

public static int UNKNOWN = 9;

public static int TOTALT = 10;

public final static int SIMP = 0;

public final static int TRAD = 1;

// 解析名称用
public static String[] javaname;

// 编码用
public static String[] nicename;

// 应用于html中的字符集
public static String[] htmlname;


public Encoding() ...{
javaname = new String[TOTALT];
nicename = new String[TOTALT];
htmlname = new String[TOTALT];
javaname[GB2312] = "GB2312";
javaname[GBK] = "GBK";
javaname[BIG5] = "BIG5";
javaname[UTF8] = "UTF8";
javaname[UNICODE] = "Unicode";
javaname[EUC_KR] = "EUC_KR";
javaname[SJIS] = "SJIS";
javaname[EUC_JP] = "EUC_JP";
javaname[ASCII] = "ASCII";
javaname[UNKNOWN] = "ISO8859_1";

// 分配编码名称
htmlname[GB2312] = "GB2312";
htmlname[GBK] = "GBK";
htmlname[BIG5] = "BIG5";
htmlname[UTF8] = "UTF-8";
htmlname[UNICODE] = "UTF-16";
htmlname[EUC_KR] = "EUC-KR";
htmlname[SJIS] = "Shift_JIS";
htmlname[EUC_JP] = "EUC-JP";
htmlname[ASCII] = "ASCII";
htmlname[UNKNOWN] = "ISO8859-1";

// 分配可读名称
nicename[GB2312] = "GB-2312";
nicename[GBK] = "GBK";
nicename[BIG5] = "Big5";
nicename[UTF8] = "UTF-8";
nicename[UNICODE] = "Unicode";
nicename[EUC_KR] = "EUC-KR";
nicename[SJIS] = "Shift-JIS";
nicename[EUC_JP] = "EUC-JP";
nicename[ASCII] = "ASCII";
nicename[UNKNOWN] = "UNKNOWN";

}


public String toEncoding(final int type) ...{
return (javaname[type] + "," + nicename[type] + "," + htmlname[type])
.intern();
}


}
Encode,java(省略,见源码)
ParseEncoding.java
package
org.loon.test.encoding;

import
java.io.ByteArrayOutputStream;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.IOException;
import
java.io.InputStream;
import
java.net.MalformedURLException;
import
java.net.URL;


/** */
/**
* <p>
* Title: LoonFramework
* </p>
* <p>
* Description:
* </p>
* <p>
* Copyright: Copyright (c) 2008
* </p>
* <p>
* Company: LoonFramework
* </p>
* <p>
* License: http://www.apache.org/licenses/LICENSE-2.0
* </p>
*
* @author chenpeng
* @email:ceponline@yahoo.com.cn
* @version 0.1
*/

public
class
ParseEncoding
extends
Encode
...
{


public ParseEncoding() ...{
super();
GB2312format = new int[94][94];
GBKformat = new int[126][191];
Big5format = new int[94][158];
EUC_KRformat = new int[94][94];
JPformat = new int[94][94];

// 初始化编码格式
init();
}


public String getEncoding(final String path) ...{
return check(getEncodeValue(path));
}


public String getEncoding(final InputStream in) ...{
return check(getEncodeValue(in));
}


public String getEncoding(final byte[] buffer) ...{
return check(getEncodeValue(buffer));
}


public String getEncoding(final URL url) ...{
return check(getEncodeValue(url));
}


private String check(final int result) ...{

if (result == -1) ...{
return nicename[UNKNOWN];
}
return nicename[result];
}


/** *//**
* 解析指定字符串路径编码所用格式
*
* @param path
* @return
*/

private int getEncodeValue(String path) ...{
int express = UNKNOWN;

if (path.startsWith("http://")) ...{

try ...{
express = getEncodeValue(new URL(path));

} catch (MalformedURLException e) ...{
express = -1;
}

} else ...{
express = getEncodeValue(new File(path));
}
return express;
}


/** *//**
*
* 解析指定InputStream所用编码,返回或然率最高的编码类型数值
*
* @param in
* @return
*/

public int getEncodeValue(InputStream in) ...{
byte[] rawtext = new byte[8192];
int bytesread = 0, byteoffset = 0;
int express = UNKNOWN;
InputStream stream = in;

try ...{
while ((bytesread = stream.read(rawtext, byteoffset, rawtext.length

- byteoffset)) > 0) ...{
byteoffset += bytesread;
}
;
stream.close();
express = getEncodeValue(rawtext);

} catch (Exception e) ...{
express = -1;
}
return express;
}


/** *//**
* 解析指定url下数据所用编码,返回或然率最高的编码类型数值
*
* @param url
* @return
*/

public int getEncodeValue(URL url) ...{

InputStream stream;

try ...{
stream = url.openStream();

} catch (IOException e) ...{
stream = null;
}

return getEncodeValue(stream);
}


/** *//**
* 解析指定file所用编码,返回或然率最高的编码类型数值
*
* @param file
* @return
*/
汉字编码是一项较为麻烦的事情,弄不好就会造出些谁都看不懂的乱码。比如我想做个针对汉字网站的爬虫系统,需要对非特定的页面进行数据解析处理,而此时我所访问的页面编码格式未知,如果不能正确处理页面编码,则很难获得我们理想中的数据。
通常这时候可能有几种选择:
一是根据response的ContentType获得,如果服务器支持的话此项中会返回charset数值,解析即可。但对不返回或者不支持的服务器则无能为力。
二是使用正则或自定义解析函数截取页面中‘charset=’后的数据,采取死钉战术,但万一采集的页面中没有此项或者此项有错,也就回天乏术。
三就是老老实实的解析全文,最后返回一个符合的编码格式。
此例中我演示了几种较常见编码的识别方法,通过统计编码为指定编码的或然率, 而后返回可能性最高的编码方式。在无法获得确切编码之时,这可说是一种唯一的选择。
这种识别方式主要是针对汉字编码而来,所以对应页面中的汉字数目越多,统计结果就越准确,反之则很难识别出正确结果。
Encoding.java


















































































































Encode,java(省略,见源码)
ParseEncoding.java



































































































































































