环境:eclipsse, jdk1.6, 没有使用第三方的包,都是JDK有的。
注意,项目源文件我都使用的是UTF-8的编码格式,如果不是,代码里面的汉字注释会显示乱码。
设置UTF-8:windows->Preferences->General->Workspace 页面上Text file encoding,选择Other UTF-8
项目结构:
1.字典文件
dic.txt 下载地址:http://download.csdn.net/detail/wssiqi/5056993
这里只摘录一部分内容,里面共收录了20902个汉字
[plain] view
plain copy
- 19968,一,一,1,1,GGLL,A,yi1,yī
- 19969,丁,一,2,12,SGH,AI,ding1,dīng,zheng1,zhēng
- 19970,丂,一,2,15,GNV,AZVV,kao3,kǎo,qiao3,qiǎo,yu2,yú
- 19971,七,一,2,15,AGN,HD,qi1,qī
- 19972,丄,一,2,21,HGD,IAVV,shang4,shàng
- 19973,丅,一,2,12,GHK,AIAA,xia4,xià
- 19974,丆,一,2,13,DGT,GDAA,han3,hǎn
- 19975,万,一,3,153,DNV,,wan4,wàn,mo4,mò
- 19976,丈,一,3,134,DYI,AOS,zhang4,zhàng
- 19977,三,一,3,111,DGGG,CD,san1,sān
- 19978,上,一,3,211,HHGG,IDA,shang3,shǎng,shang4,shàng
- 19979,下,一,3,124,GHI,AID,xia4,xià
- 19980,丌,一,3,132,GJK,AND,ji1,jī,qi2,qí
- 19981,不,一,4,1324,GII,GI,fou3,fǒu,bu4,bù
- 19982,与,一,3,151,GNGD,AZA,yu4,yù,yu3,yǔ,yu2,yú
- 19983,丏,一,4,1255,GHNN,AIZY,mian3,miǎn
- 19984,丐,一,4,1215,GHNV,AIZ,gai4,gài
- 19985,丑,一,4,5211,NFD,XED,chou3,chǒu
- 19986,丒,一,4,5341,VYGF,YDSA,chou3,chǒu
2.Dic.java
[java] view
plain copy
- package com.siqi.dict;
- import java.io.BufferedReader;
- import java.io.ByteArrayInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.InputStreamReader;
- import java.nio.charset.Charset;
- /**
- * 汉字本地字典。 <br/>
- * 本地字典数据来自于<a href=http://www.zdic.net/search/?c=2>汉典</a>
- * 实现了一下常用的需求,例如返回拼音,五笔,拼音首字母,笔画数目,笔画顺序。
- *
- * @author siqi
- *
- */
- public class Dic {
- /**
- * 设置是否输出调试信息
- */
- private static boolean DEBUG = true;
- /**
- * 默认编码
- */
- public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
- /**
- * 汉字Unicode最小编码
- */
- public static final int CN_U16_CODE_MIN = 0x4e00;
- /**
- * 汉字Unicode最大编码
- */
- public static final int CN_U16_CODE_MAX = 0x9fa5;
- /**
- * 本地字典文件名
- */
- public static final String DIC_FILENAME = "dic.txt";
- /**
- * 字典数据
- */
- public static byte[] bytes = new byte[0];
- /**
- * 字典汉字数目
- */
- public static int count = 0;
- /**
- * 汉字unicode值在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_UNICODE = 0;
- /**
- * 汉字在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_CHARACTER = 1;
- /**
- * 汉字部首在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_BUSHOU = 2;
- /**
- * 汉字笔画在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_BIHUA = 3;
- /**
- * 汉字笔画顺序在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_BISHUN = 4;
- /**
- * 汉字五笔在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_WUBI = 5;
- /**
- * 汉字郑码在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_ZHENGMA = 6;
- /**
- * 第一个汉字拼音(英文字母)在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_PINYIN_EN = 7;
- /**
- * 第一个汉字拼音(中文字母)在一条汉字信息的位置<br/>
- * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá"
- */
- public static int INDEX_PINYIN_CN = 8;
- /**
- * 装载字典
- */
- static {
- long time = System.currentTimeMillis();
- try {
- LoadDictionary();
- count = count();
- if (DEBUG) {
- System.out.println("成功载入字典" + new File(DIC_FILENAME).getCanonicalPath() + " ,用时:"
- + (System.currentTimeMillis() - time) + "毫秒,载入字符数"+count);
- }
- } catch (Exception e) {
- try {
- System.out.println("载入字典失败" + new File(DIC_FILENAME).getCanonicalPath()+"\r\n");
- } catch (Exception e1) {
- }
- e.printStackTrace();
- }
- }
- /**
- * 获取汉字unicode值
- *
- * @param ch
- * 汉字
- * @return 返回汉字的unicode值
- * @throws Exception
- */
- public static String GetUnicode(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_UNICODE);
- }
- /**
- * 获取拼音(英文字母)
- *
- * @param ch
- * 单个汉字字符
- * @return 返回汉字的英文字母拼音。如 "大"->"da4"。
- * @throws Exception
- */
- public static String GetPinyinEn(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_PINYIN_EN);
- }
- /**
- * 返回汉字字符串的拼音(英文字母)
- *
- * @param str
- * 汉字字符串
- * @return 返回汉字字符串的拼音。将字符串中的汉字替换成拼音,其他字符不变。拼音中间会有空格。 注意,对于多音字,返回的拼音可能不正确。
- * @throws Exception
- */
- public static String GetPinyinEn(String str) throws Exception {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < str.length(); i++) {
- char ch = str.charAt(i);
- if (isChineseChar(ch)) {
- sb.append(GetPinyinEn(ch) + " ");
- } else {
- sb.append(ch);
- }
- }
- return sb.toString().trim();
- }
- /**
- * 获取拼音(中文字母)
- *
- * @param ch
- * 单个汉字字符
- * @return 返回汉字的中文字母拼音。如 "打"->"dǎ"。
- * @throws Exception
- */
- public static String GetPinyinCn(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_PINYIN_CN);
- }
- /**
- * 返回汉字字符串的拼音(中文字母)
- *
- * @param str
- * 汉字字符串
- * @return 返回汉字字符串的拼音。将字符串中的汉字替换成拼音,其他字符不变。拼音中间会有空格。 注意,对于多音字,返回的拼音可能不正确。
- * @throws Exception
- */
- public static String GetPinyinCn(String str) throws Exception {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < str.length(); i++) {
- char ch = str.charAt(i);
- if (isChineseChar(ch)) {
- sb.append(GetPinyinCn(ch) + " ");
- } else {
- sb.append(ch);
- }
- }
- return sb.toString().trim();
- }
- /**
- * 返回拼音首字母
- *
- * @param ch
- * @return
- * @throws Exception
- */
- public static String GetFirstLetter(Character ch) throws Exception {
- if (isChineseChar(ch)) {
- return GetPinyinEn(ch).substring(0, 1);
- } else {
- return "";
- }
- }
- /**
- * 返回汉字字符串拼音首字母,如果不是汉字,会被忽略掉。
- *
- * @param str
- * 汉字字符串
- * @return
- * @throws Exception
- */
- public static String GetFirstLetter(String str) throws Exception {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < str.length(); i++) {
- char ch = str.charAt(i);
- if (isChineseChar(ch)) {
- sb.append(GetFirstLetter(ch));
- }
- }
- return sb.toString().trim();
- }
- /**
- * 获取汉字部首
- *
- * @param ch
- * 汉字
- * @return 返回汉字的部首
- * @throws Exception
- */
- public static String GetBushou(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_BUSHOU);
- }
- /**
- * 获取汉字笔画数目
- *
- * @param ch
- * 汉字
- * @return 返回汉字的笔画数目
- * @throws Exception
- */
- public static String GetBihua(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_BIHUA);
- }
- /**
- * 获取汉字笔画顺序
- *
- * @param ch
- * 汉字
- * @return 返回汉字的笔画顺序
- * @throws Exception
- */
- public static String GetBishun(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_BISHUN);
- }
- /**
- * 获取汉字五笔
- *
- * @param ch
- * 汉字
- * @return 返回汉字五笔
- * @throws Exception
- */
- public static String GetWubi(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_WUBI);
- }
- /**
- * 获取汉字郑码
- *
- * @param ch
- * 汉字
- * @return 返回汉字郑码
- * @throws Exception
- */
- public static String GetZhengma(Character ch) throws Exception {
- return GetCharInfo(ch, INDEX_ZHENGMA);
- }
- /**
- * 从字典中获取汉字信息
- *
- * @param ch
- * 要查询的汉字
- * @return 返回汉字信息,如"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" <br/>
- * 第一是汉字unicode值<br/>
- * 第二是汉字<br/>
- * 第三是汉字部首<br/>
- * 第四是汉字笔画<br/>
- * 第五是汉字笔画顺序("12345"分别代表"横竖撇捺折")<br/>
- * 第六是汉字五笔<br/>
- * 第七是汉字郑码<br/>
- * 第八及以后是汉字的拼音(英文字母拼音和中文字母拼音)<br/>
- * @throws Exception
- */
- public static String GetCharInfo(Character ch) throws Exception {
- if (!isChineseChar(ch)) {
- throw new Exception("‘" + ch + "‘ 不是一个汉字!");
- }
- String result = "";
- ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
- BufferedReader br = new BufferedReader(new InputStreamReader(bais));
- String strWord;
- while ((strWord = br.readLine()) != null) {
- if (strWord.startsWith(String.valueOf(ch.hashCode()))) {
- result = strWord;
- break;
- }
- }
- br.close();
- bais.close();
- return result;
- }
- /**
- * 返回汉字信息
- *
- * @param ch
- * 汉字
- * @param index
- * 信息所在的Index
- * @return
- * @throws Exception
- */
- private static String GetCharInfo(Character ch, int index) throws Exception {
- if (!isChineseChar(ch)) {
- throw new Exception("‘" + ch + "‘ 不是一个汉字!");
- }
- // 获取汉字信息
- String charInfo = GetCharInfo(ch);
- String result = "";
- try {
- result = charInfo.split(",")[index];
- } catch (Exception e) {
- throw new Exception("请查看字典中" + ch + "汉字记录是否正确!");
- }
- return result;
- }
- /**
- * 载入字典文件到内存。
- * @throws Exception
- */
- private static void LoadDictionary() throws Exception {
- File file = new File(DIC_FILENAME);
- bytes = new byte[(int) file.length()];
- FileInputStream fis = new FileInputStream(file);
- fis.read(bytes, 0, bytes.length);
- fis.close();
- }
- /**
- * 判断字符是否为汉字,在测试的时候,我发现汉字的字符的hashcode值 跟汉字Unicode
- * 16的值一样,所以可以用hashcode来判断是否为汉字。
- *
- * @param ch
- * 汉字
- * @return 是汉字返回true,否则返回false。
- */
- public static boolean isChineseChar(Character ch) {
- if (ch.hashCode() >= CN_U16_CODE_MIN
- && ch.hashCode() <= CN_U16_CODE_MAX) {
- return true;
- } else {
- return false;
- }
- }
- /**
- *
- * @return 返回字典包含的汉字数目。
- * @throws Exception
- */
- private static int count() throws Exception {
- int cnt = 0;
- ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
- BufferedReader br = new BufferedReader(new InputStreamReader(bais));
- while (br.readLine() != null) {
- cnt++;
- }
- br.close();
- bais.close();
- return cnt;
- }
- }
3.Sample.java
如何使用字典
[java] view
plain copy
- package com.siqi.dict;
- /**
- * 包含两个实例,示例如何获取汉字的拼音等信息。
- * @author siqi
- *
- */
- public class Sample {
- /**
- * 字典使用实例
- *
- * @param args
- */
- public static void main(String[] args) {
- try {
- long time = System.currentTimeMillis();
- char ch = ‘打‘;
- //汉字单个字符
- System.out.println("====打字信息开始====");
- System.out.println("首字母:"+Dic.GetFirstLetter(ch));
- System.out.println("拼音(中):"+Dic.GetPinyinCn(ch));
- System.out.println("拼音(英):"+Dic.GetPinyinEn(ch));
- System.out.println("部首:"+Dic.GetBushou(ch));
- System.out.println("笔画数目:"+Dic.GetBihua(ch));
- System.out.println("笔画:"+Dic.GetBishun(ch));
- System.out.println("五笔:"+Dic.GetWubi(ch));
- System.out.println("====打字信息结束====");
- //汉字字符串
- System.out.println("\r\n====汉字字符串====");
- System.out.println(Dic.GetPinyinEn("返回汉字字符串的拼音。"));
- System.out.println(Dic.GetPinyinCn("返回汉字字符串的拼音。"));
- System.out.println(Dic.GetFirstLetter("返回汉字字符串的拼音。"));
- System.out.println("====汉字字符串====\r\n");
- System.out.println("用时:"+(System.currentTimeMillis()-time)+"毫秒");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
4.结果
[html] view
plain copy
- ====打字信息开始====
- 成功载入字典C:\workspaces\01_java\DictLocal\dic.txt ,用时:15毫秒,载入字符数20902
- 首字母:d
- 拼音(中):dǎ
- 拼音(英):da3
- 部首:扌
- 笔画数目:5
- 笔画:12112
- 五笔:RSH
- ====打字信息结束====
- ====汉字字符串====
- fan3 hui2 han4 zi4 zi4 fu2 chuan4 di2 pin1 yin1 。
- fǎn huí hàn zì zì fú chuàn dí pīn yīn 。
- fhhzzfcdpy
- ====汉字字符串====
- Memory(Used/Total) : 1539/15872 KB
- 用时:218毫秒
待会再上传如何获取字典文件的,我是通过收集http://www.zdic.net/zd/的网页来获取的
=============补充,如何获取汉字的信息================
=============所有的信息都是从汉典网站上获取的=========
目录结构为:
环境:eclipsse, jdk1.6, 没有使用第三方的包,都是JDK有的。
注意,项目源文件我都使用的是UTF-8的编码格式,如果不是,代码里面的汉字注释会显示乱码。
设置UTF-8:windows->Preferences->General->Workspace 页面上Text file encoding,选择Other UTF-8
包说明:
com.siqi.http
Httpclient.Java是我写的一个简单的获取网页的类,用来获取网页内容;
com.siqi.dict
DictMain.java用来下载汉字网页,从中获取汉字的拼音信息,并保存到data.dat中
DownloadThread.java用来下载网页(多线程)
com.siqi.pinyin
PinYin.java在执行过DictMain.java后,会生成一个data.dat,把这个文件拷贝到com.siqi.pinyin包下面,就可以调用PinYin.java里面的函数得到汉字的拼音了
PinYinEle.java一个汉字->拼音->Unicode的模型
源码:
Httpclient.java 可以用来获取网页,可以的到网页内容,网页编码和网页的header,简版
[java] view
plain copy
- package com.siqi.http;
- import java.io.IOException;
- import java.io.InputStream;
- import java.net.Socket;
- import java.net.URLEncoder;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- /**
- * 使用SOCKET实现简单的网页GET和POST
- *
- * @author siqi
- *
- */
- public class Httpclient {
- /**
- * processUrl 参数 HTTP GET
- */
- public static final int METHOD_GET = 0;
- /**
- * processUrl 参数 HTTP POST
- */
- public static final int METHOD_POST = 1;
- /**
- * HTTP GET的报头,简化版
- */
- public static final String HEADER_GET = "GET %s HTTP/1.0\r\nHOST: %s\r\n\r\n";
- /**
- * HTTP POST的报头,简化版
- */
- public static final String HEADER_POST = "POST %s HTTP/1.0\r\nHOST: %s\r\nContent-Length: 0\r\n\r\n";
- /**
- * 网页报头和内容的分割符
- */
- public static final String CONTENT_SEPARATOR = "\r\n\r\n";
- /**
- * 网页请求响应内容byte
- */
- private byte[] bytes = new byte[0];
- /**
- * 网页报头
- */
- private String header = "";
- /**
- * 网页内容
- */
- private String content = "";
- /**
- * 网页编码,默认为UTF-8
- */
- public static final String CHARSET_DEFAULT = "UTF-8";
- /**
- * 网页编码
- */
- private String charset = CHARSET_DEFAULT;
- /**
- * 使用Httpclient的例子
- *
- * @param args
- * @throws Exception
- */
- public static void main(String[] args) throws Exception {
- Httpclient httpclient = new Httpclient();
- // 请求百度首页(手机版)
- httpclient.processUrl("http://m.baidu.com/");
- System.out.println("获取网页http://m.baidu.com/");
- System.out.println("报头为:\r\n" + httpclient.getHeader());
- System.out.println("内容为:\r\n" + httpclient.getContent());
- System.out.println("编码为:\r\n" + httpclient.getCharset());
- System.out.println("************************************");
- // 使用百度搜索"中国"(手机版)
- // 这是手机百度搜索框的源码 <input id="word" type="text" size="20" maxlength="64"
- // name="word">
- String url = String.format("http://m.baidu.com/s?word=%s",
- URLEncoder.encode("中国", CHARSET_DEFAULT));
- httpclient.processUrl(url, METHOD_POST);
- System.out.println("获取网页http://m.baidu.com/s?word=中国");
- System.out.println("报头为:\r\n" + httpclient.getHeader());
- System.out.println("内容为:\r\n" + httpclient.getContent());
- System.out.println("编码为:\r\n" + httpclient.getCharset());
- }
- /**
- * 初始化,设置所有变量为默认值
- */
- private void init() {
- this.bytes = new byte[0];
- this.charset = CHARSET_DEFAULT;
- this.header = "";
- this.content = "";
- }
- /**
- * 获取网页报头header
- *
- * @return
- */
- public String getHeader() {
- return header;
- }
- /**
- * 获取网页内容content
- *
- * @return
- */
- public String getContent() {
- return content;
- }
- /**
- * 获取网页编码
- *
- * @return
- */
- public String getCharset() {
- return charset;
- }
- /**
- * 请求网页内容(使用HTTP GET)
- *
- * @param url
- * @throws Exception
- */
- public void processUrl(String url) throws Exception {
- processUrl(url, METHOD_GET);
- }
- /**
- * 使用Socket请求(获取)一个网页。<br/>
- * 例如:<br/>
- * processUrl("http://www.baidu.com/", METHOD_GET)会获取百度首页;<br/>
- *
- * @param url
- * 这个网页或者网页内容的地址
- * @param method
- * 请求网页的方法: METHOD_GET或者METHOD_POST
- * @throws Exception
- */
- public void processUrl(String url, int method) throws Exception {
- init();
- // url = "http://www.zdic.net/search/?c=2&q=%E5%A4%A7";
- // 规范化链接,当网址为http://www.baidu.com时,将网址变为:http://www.baidu.com/
- Matcher mat = Pattern.compile("https?://[^/]+").matcher(url);
- if (mat.find() && mat.group().equals(url)) {
- url += "/";
- }
- Socket socket = new Socket(getHostUrl(url), 80); // 设置要连接的服务器地址
- socket.setSoTimeout(3000); // 设置超时时间为3秒
- String request = null;
- // 构造请求,详情请参考HTTP协议(RFC2616)
- if (method == METHOD_POST) {
- request = String.format(HEADER_POST, getSubUrl(url),
- getHostUrl(url));
- } else {
- request = String
- .format(HEADER_GET, getSubUrl(url), getHostUrl(url));
- }
- socket.getOutputStream().write(request.getBytes());// 发送请求
- this.bytes = InputStream2ByteArray(socket.getInputStream());// 读取响应
- // 获取网页编码,我们只需要测试查找前4096个字节,一般编码信息都会在里面找到
- String temp = new String(this.bytes, 0,
- bytes.length < 4096 ? bytes.length : 4096);
- mat = Pattern.compile("(?<=<meta.{0,100}?charset=)[a-z-0-9]*",
- Pattern.CASE_INSENSITIVE).matcher(temp);
- if (mat.find()) {
- this.charset = mat.group();
- } else {
- this.charset = CHARSET_DEFAULT;
- }
- // 用正确的编码得到网页报头和内容
- temp = new String(this.bytes, this.charset);
- int headerEnd = temp.indexOf(CONTENT_SEPARATOR);
- this.header = temp.substring(0, headerEnd);
- this.content = temp.substring(headerEnd + CONTENT_SEPARATOR.length(),
- temp.length());
- socket.close(); // 关闭socket
- }
- /**
- * 根据网址,获取服务器地址<br/>
- * 例如:<br/>
- * http://m.weathercn.com/common/province.jsp
- * <p>
- * 返回:<br/>
- * m.weathercn.com
- *
- * @param url
- * 网址
- * @return
- */
- public static String getHostUrl(String url) {
- String host = "";
- Matcher mat = Pattern.compile("(?<=https?://).+?(?=/)").matcher(url);
- if (mat.find()) {
- host = mat.group();
- }
- return host;
- }
- /**
- * 根据网址,获取网页路径 例如:<br/>
- * http://m.weathercn.com/common/province.jsp
- * <p>
- * 返回:<br/>
- * /common/province.jsp
- *
- * @param url
- * @return 如果没有获取到网页路径,返回"";
- */
- public static String getSubUrl(String url) {
- String subUrl = "";
- Matcher mat = Pattern.compile("https?://.+?(?=/)").matcher(url);
- if (mat.find()) {
- subUrl = url.substring(mat.group().length());
- }
- return subUrl;
- }
- /**
- * 将b1和b2两个byte数组拼接成一个, 结果=b1+b2
- *
- * @param b1
- * @param b2
- * @return
- */
- public static byte[] ByteArrayCat(byte[] b1, byte[] b2) {
- byte[] b = new byte[b1.length + b2.length];
- System.arraycopy(b1, 0, b, 0, b1.length);
- System.arraycopy(b2, 0, b, b1.length, b2.length);
- return b;
- }
- /**
- * 读取输入流并转为byte数组,不返回字符串, 是因为输入流的编码不确定,错误的编码会造成乱码。
- *
- * @param is
- * 输入流inputstream
- * @return 字符串
- * @throws IOException
- */
- public static byte[] InputStream2ByteArray(InputStream is)
- throws IOException {
- byte[] b = new byte[0];
- byte[] bb = new byte[4096]; // 缓冲区
- int len = 0;
- while ((len = is.read(bb)) != -1) {
- byte[] newb = new byte[b.length + len];
- System.arraycopy(b, 0, newb, 0, b.length);
- System.arraycopy(bb, 0, newb, b.length, len);
- b = newb;
- }
- return b;
- }
- }
DictMain.java
[java] view
plain copy
- package com.siqi.dict;
- import java.io.File;
- import java.io.FileReader;
- import java.io.FileWriter;
- import java.io.IOException;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- /**
- * 从汉典下载汉字网页,并提取拼音信息
- * @author siqi
- *
- */
- public class DictMain {
- /**
- * 网页保存路径
- */
- public static final String SAVEPATH = "dict/pages/";
- /**
- * 下载的汉字网页名称
- */
- public static final String FILEPATH = SAVEPATH + "%s.html";
- /**
- * 字典数据文件名称
- */
- public static final String DATA_FILENAME = "data.txt";
- /**
- * 汉字unicode最小
- */
- public static final int UNICODE_MIN = 0x4E00;
- /**
- * 汉字unicode最大
- */
- public static final int UNICODE_MAX = 0x9FFF;
- /**
- * 准备工作:
- * 1.从汉典网站下载所有汉字的页面,注意,不要在eclipse中打开保存页面的文件夹,
- * 因为每个汉字一个页面,总共有20000+个页面,容易卡死eclipse
- * 2.从汉字页面获取汉字拼音信息,生成data.dat文件
- * 3.生成的data.dat复制到com.siqi.pinyin下面
- * 4.可以使用com.siqi.pinyin.PinYin.java了
- */
- static{
- // 下载网页
- for (int i = UNICODE_MIN; i <= UNICODE_MAX; i++) {
- // 检查是否已经存在
- String filePath = String.format(FILEPATH, i); // 文件名
- File file = new File(filePath);
- if (!file.exists()) {
- new DownloadThread(i).start();
- }
- }
- //解析网页,得到拼音信息,并保存到data.dat
- StringBuffer sb = new StringBuffer();
- for (int i = UNICODE_MIN; i <= UNICODE_MAX; i++) {
- String word = new String(Character.toChars(i));
- String pinyin = getPinYinFromWebpageFile(String.format(FILEPATH, i));
- String str = String.format("%s,%s,%s\r\n", i,word,pinyin);
- System.out.print(str);
- sb.append(str);
- }
- //保存到data.dat
- try {
- FileWriter fw = new FileWriter(DATA_FILENAME);
- fw.write(sb.toString());
- fw.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args){
- System.out.println("All prepared!");
- }
- /**
- * 从网页文件获取拼音信息
- * @param file
- * @return
- */
- private static String getPinYinFromWebpageFile(String file) {
- try {
- char[] buff = new char[(int) new File(file).length()];
- FileReader reader = new FileReader(file);
- reader.read(buff);
- reader.close();
- String content = new String(buff);
- // spf("yi1")
- Matcher mat = Pattern.compile("(?<=spf\\(\")[a-z1-4]{0,100}",
- Pattern.CASE_INSENSITIVE).matcher(content);
- if (mat.find()) {
- return mat.group();
- }
- //<span class="dicpy">cal</span> spf("xin1")
- mat = Pattern.compile("(?<=class=\"dicpy\">)[a-z1-4]{0,100}",
- Pattern.CASE_INSENSITIVE).matcher(content);
- if (mat.find()) {
- return mat.group();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "";
- }
- }
DownloadThread.java
[java] view
plain copy
- package com.siqi.dict;
- import java.io.File;
- import java.io.FileWriter;
- import java.net.URLEncoder;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import com.siqi.http.Httpclient;
- /**
- * 将汉字页面从汉典网站下载下来,存储到本地
- * http://www.zdic.net/search/?c=2
- * @author siqi
- *
- */
- public class DownloadThread extends Thread{
- /**
- * 线程最大数目
- */
- public static int THREAD_MAX = 10;
- /**
- * 下载最大重复次数
- */
- public static int RETRY_MAX = 5;
- /**
- * 汉典网站搜索网址
- */
- public static String SEARCH_URL = "http://www.zdic.net/search/?q=%s";
- /**
- * 当前线程数目
- */
- private static int threadCnt = 0;
- /**
- * 当前线程处理汉字的unicode编码
- */
- private int unicode = 0;
- /**
- * 如果PATH文件夹不存在,那么创建它
- */
- static{
- try {
- File file = new File(DictMain.SAVEPATH);
- if (!file.exists()) {
- file.mkdirs();
- }
- } catch (Exception e) {
- }
- }
- /**
- * 返回当前线程数量
- * @param i 修改当前线程数量 threadCnt += i;
- * @return 返回修改后线程数量
- */
- public static synchronized int threadCnt(int i){
- threadCnt += i;
- return threadCnt;
- }
- /**
- * 下载UNICODE编码为unicode的汉字网页
- * @param unicode
- */
- public DownloadThread(int unicode){
- //等待,直到当前线程数量小于THREAD_MAX
- while(threadCnt(0)>THREAD_MAX){
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- }
- }
- threadCnt(1); //线程数量+1
- this.unicode = unicode;
- }
- @Override
- public void run() {
- long t1 = System.currentTimeMillis(); // 记录时间
- String filePath = String.format(DictMain.FILEPATH, unicode); // 文件名
- String word = new String(Character.toChars(unicode)); // 将unicode转换为数字
- boolean downloaded = false;
- int retryCnt = 0; // 下载失败重复次数
- while (!downloaded && retryCnt < RETRY_MAX) {
- try {
- String content = DownloadPage(word);
- SaveToFile(filePath, content);
- downloaded = true;
- threadCnt(-1);
- System.out.println(String.format("%s, %s, 下载成功!线程数目:%s 用时:%s",
- unicode, word, threadCnt(0), System.currentTimeMillis()
- - t1));
- return;
- } catch (Exception e) {
- retryCnt++;
- }
- }
- threadCnt(-1);
- System.err.println(String.format("%s, %s, 下载失败!线程数目:%s 用时:%s", unicode,
- word, threadCnt(0), System.currentTimeMillis() - t1));
- }
- /**
- * 在汉典网站上查找汉字,返回汉字字典页面内容
- * @param word
- * @return
- * @throws Exception
- */
- public String DownloadPage(String word) throws Exception{
- //查找word
- Httpclient httpclient = new Httpclient();
- String url = String.format(SEARCH_URL, URLEncoder.encode(word, "UTF-8"));
- httpclient.processUrl(url, Httpclient.METHOD_POST);
- //返回的是一个跳转页
- //获取跳转的链接
- Matcher mat = Pattern.compile("(?<=HREF=\")[^\"]+").matcher(httpclient.getContent());
- if(mat.find()){
- httpclient.processUrl(mat.group());
- }
- return httpclient.getContent();
- }
- /**
- * 将内容content写入file文件
- * @param file
- * @param content
- */
- public void SaveToFile(String file, String content){
- try {
- FileWriter fw = new FileWriter(file);
- fw.write(content);
- fw.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
PinYin.java
[java] view
plain copy
- package com.siqi.pinyin;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- import java.util.HashMap;
- import java.util.Map;
- public class PinYin {
- private static Map<Integer, PinYinEle> map = new HashMap<Integer, PinYinEle>();
- /**
- * 载入pinyin数据文件
- */
- static {
- try {
- BufferedReader bReader = new BufferedReader(new InputStreamReader(
- PinYin.class.getResourceAsStream("data.dat")));
- String aLine = null;
- while ((aLine = bReader.readLine()) != null) {
- PinYinEle ele = new PinYinEle(aLine);
- map.put(ele.getUnicode(), ele);
- }
- bReader.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 去掉注释可以测试一下
- *
- * @param args
- */
- public static void main(String[] args) {
- System.out.println(" 包含声调:" + PinYin.getPinYin("大家haome12345"));
- System.out.println("不包含声调:" + PinYin.getPinYin("大家haome12345", false));
- }
- /**
- * 获取汉字字符串的拼音,containsNumber是否获取拼音中的声调1、2、3、4
- *
- * @param str
- * @param containsNumber
- * true = 包含声调,false = 不包含声调
- * @return
- */
- public static String getPinYin(String str, boolean containsNumber) {
- StringBuffer sb = new StringBuffer();
- for (Character ch : str.toCharArray()) {
- sb.append(getPinYin(ch, containsNumber));
- }
- return sb.toString();
- }
- /**
- * 获取字符串的拼音
- *
- * @param str
- * @return
- */
- public static String getPinYin(String str) {
- StringBuffer sb = new StringBuffer();
- for (Character ch : str.toCharArray()) {
- sb.append(getPinYin(ch));
- }
- return sb.toString();
- }
- /**
- * 获取单个汉字的拼音,包含声调
- *
- * @param ch
- * @return
- */
- public static String getPinYin(Character ch) {
- return getPinYin(ch, true);
- }
- /**
- * 获取单个汉字的拼音
- *
- * @param ch
- * 汉字. 如果输入非汉字,返回ch. 如果输入null,返回空字符串;
- * @param containsNumber
- * true = 包含声调,false = 不包含声调
- * @return
- */
- public static String getPinYin(Character ch, boolean containsNumber) {
- if (ch != null) {
- int code = ch.hashCode();
- if (map.containsKey(code)) {
- if (containsNumber) {
- return map.get(code).getPinyin();
- } else {
- return map.get(code).getPinyin().replaceAll("[0-9]", "");
- }
- } else {
- return ch.toString();
- }
- }
- return "";
- }
- }
PinYinEle.java
[java] view
plain copy
- package com.siqi.pinyin;
- public class PinYinEle {
- private int unicode;
- private String ch;
- private String pinyin;
- public PinYinEle(){}
- public PinYinEle(String str){
- if(str!=null){
- String[] strs = str.split(",");
- if(strs.length == 3){
- try{
- this.unicode = Integer.parseInt(strs[0]);
- }catch(Exception e){
- }
- this.ch = strs[1];
- this.pinyin = strs[2];
- }
- }
- }
- public int getUnicode() {
- return unicode;
- }
- public void setUnicode(int unicode) {
- this.unicode = unicode;
- }
- public String getCh() {
- return ch;
- }
- public void setCh(String ch) {
- this.ch = ch;
- }
- public String getPinyin() {
- return pinyin;
- }
- public void setPinyin(String pinyin) {
- this.pinyin = pinyin;
- }
- }
生成的data.dat里面内容(部分)为:
[java] view
plain copy
- 19968,一,yi1
- 19969,丁,ding1
- 19970,丂,kao3
- 19971,七,qi1
- 19972,丄,shang4
- 19973,丅,xia4
- 19974,丆,han3
- 19975,万,wan4
- 19976,丈,zhang4
- 19977,三,san1
- 19978,上,shang4
- 19979,下,xia4
- 19980,丌,qi2
- 19981,不,bu4
运行DictMain.java结果
执行时间可能会有几十分钟到几小时不等,总共会下载200+M的网页(20000+个网页),每次运行都会先判断以前下载过没有,所以结束掉程序不会有影响
显示All prepared!表示已经准备好了,刷新项目文件夹,可以看到网页保持在dict/pages下面,不建议在elipse中打开那个文件夹,因为里面有2万多个文件,会卡死eclipse,
还可以看到生成了data.txt文件,改为data.dat并复制到pinyin文件夹下面
运行PinYin.java
可以看到"大家haome12345"的拼音:
[java] view
plain copy
- 包含声调:da4jia1haome12345
- 包含声调:dajiahaome12345
上面只是显示了如何获取拼音,获取笔画等的方法类似,在这里就不演示了。