java实现汉字字典

来源:互联网 发布:潜韵耳机的官方淘宝店 编辑:程序博客网 时间:2024/04/29 05:53

环境: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
  1. 19968,一,一,1,1,GGLL,A,yi1,yī  
  2. 19969,丁,一,2,12,SGH,AI,ding1,dīng,zheng1,zhēng  
  3. 19970,丂,一,2,15,GNV,AZVV,kao3,kǎo,qiao3,qiǎo,yu2,yú  
  4. 19971,七,一,2,15,AGN,HD,qi1,qī  
  5. 19972,丄,一,2,21,HGD,IAVV,shang4,shàng  
  6. 19973,丅,一,2,12,GHK,AIAA,xia4,xià  
  7. 19974,丆,一,2,13,DGT,GDAA,han3,hǎn  
  8. 19975,万,一,3,153,DNV,,wan4,wàn,mo4,mò  
  9. 19976,丈,一,3,134,DYI,AOS,zhang4,zhàng  
  10. 19977,三,一,3,111,DGGG,CD,san1,sān  
  11. 19978,上,一,3,211,HHGG,IDA,shang3,shǎng,shang4,shàng  
  12. 19979,下,一,3,124,GHI,AID,xia4,xià  
  13. 19980,丌,一,3,132,GJK,AND,ji1,jī,qi2,qí  
  14. 19981,不,一,4,1324,GII,GI,fou3,fǒu,bu4,bù  
  15. 19982,与,一,3,151,GNGD,AZA,yu4,yù,yu3,yǔ,yu2,yú  
  16. 19983,丏,一,4,1255,GHNN,AIZY,mian3,miǎn  
  17. 19984,丐,一,4,1215,GHNV,AIZ,gai4,gài  
  18. 19985,丑,一,4,5211,NFD,XED,chou3,chǒu  
  19. 19986,丒,一,4,5341,VYGF,YDSA,chou3,chǒu  

2.Dic.java

[java] view plain copy
  1. package com.siqi.dict;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.ByteArrayInputStream;  
  5. import java.io.File;  
  6. import java.io.FileInputStream;  
  7. import java.io.InputStreamReader;  
  8. import java.nio.charset.Charset;  
  9.   
  10. /** 
  11.  * 汉字本地字典。 <br/> 
  12.  * 本地字典数据来自于<a href=http://www.zdic.net/search/?c=2>汉典</a> 
  13.  * 实现了一下常用的需求,例如返回拼音,五笔,拼音首字母,笔画数目,笔画顺序。 
  14.  *  
  15.  * @author siqi 
  16.  *  
  17.  */  
  18. public class Dic {  
  19.   
  20.     /** 
  21.      * 设置是否输出调试信息 
  22.      */  
  23.     private static boolean DEBUG = true;  
  24.   
  25.     /** 
  26.      * 默认编码 
  27.      */  
  28.     public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");  
  29.   
  30.     /** 
  31.      * 汉字Unicode最小编码 
  32.      */  
  33.     public static final int CN_U16_CODE_MIN = 0x4e00;  
  34.   
  35.     /** 
  36.      * 汉字Unicode最大编码 
  37.      */  
  38.     public static final int CN_U16_CODE_MAX = 0x9fa5;  
  39.   
  40.     /** 
  41.      * 本地字典文件名 
  42.      */  
  43.     public static final String DIC_FILENAME = "dic.txt";  
  44.   
  45.     /** 
  46.      * 字典数据 
  47.      */  
  48.     public static byte[] bytes = new byte[0];  
  49.       
  50.     /** 
  51.      * 字典汉字数目 
  52.      */  
  53.     public static int count = 0;  
  54.   
  55.     /** 
  56.      * 汉字unicode值在一条汉字信息的位置<br/> 
  57.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  58.      */  
  59.     public static int INDEX_UNICODE = 0;  
  60.     /** 
  61.      * 汉字在一条汉字信息的位置<br/> 
  62.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  63.      */  
  64.     public static int INDEX_CHARACTER = 1;  
  65.     /** 
  66.      * 汉字部首在一条汉字信息的位置<br/> 
  67.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  68.      */  
  69.     public static int INDEX_BUSHOU = 2;  
  70.     /** 
  71.      * 汉字笔画在一条汉字信息的位置<br/> 
  72.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  73.      */  
  74.     public static int INDEX_BIHUA = 3;  
  75.     /** 
  76.      * 汉字笔画顺序在一条汉字信息的位置<br/> 
  77.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  78.      */  
  79.     public static int INDEX_BISHUN = 4;  
  80.     /** 
  81.      * 汉字五笔在一条汉字信息的位置<br/> 
  82.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  83.      */  
  84.     public static int INDEX_WUBI = 5;  
  85.     /** 
  86.      * 汉字郑码在一条汉字信息的位置<br/> 
  87.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  88.      */  
  89.     public static int INDEX_ZHENGMA = 6;  
  90.     /** 
  91.      * 第一个汉字拼音(英文字母)在一条汉字信息的位置<br/> 
  92.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  93.      */  
  94.     public static int INDEX_PINYIN_EN = 7;  
  95.     /** 
  96.      * 第一个汉字拼音(中文字母)在一条汉字信息的位置<br/> 
  97.      * 汉字信息,例:"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" 
  98.      */  
  99.     public static int INDEX_PINYIN_CN = 8;  
  100.   
  101.     /** 
  102.      * 装载字典 
  103.      */  
  104.     static {  
  105.         long time = System.currentTimeMillis();  
  106.           
  107.         try {  
  108.             LoadDictionary();  
  109.             count = count();  
  110.             if (DEBUG) {  
  111.                 System.out.println("成功载入字典" + new File(DIC_FILENAME).getCanonicalPath() + " ,用时:"  
  112.                         + (System.currentTimeMillis() - time) + "毫秒,载入字符数"+count);  
  113.             }  
  114.         } catch (Exception e) {  
  115.             try {  
  116.                 System.out.println("载入字典失败" + new File(DIC_FILENAME).getCanonicalPath()+"\r\n");  
  117.             } catch (Exception e1) {  
  118.             }  
  119.             e.printStackTrace();  
  120.         }  
  121.   
  122.     }  
  123.   
  124.     /** 
  125.      * 获取汉字unicode值 
  126.      *  
  127.      * @param ch 
  128.      *            汉字 
  129.      * @return 返回汉字的unicode值 
  130.      * @throws Exception 
  131.      */  
  132.     public static String GetUnicode(Character ch) throws Exception {  
  133.         return GetCharInfo(ch, INDEX_UNICODE);  
  134.     }  
  135.   
  136.     /** 
  137.      * 获取拼音(英文字母) 
  138.      *  
  139.      * @param ch 
  140.      *            单个汉字字符 
  141.      * @return 返回汉字的英文字母拼音。如 "大"->"da4"。 
  142.      * @throws Exception 
  143.      */  
  144.     public static String GetPinyinEn(Character ch) throws Exception {  
  145.         return GetCharInfo(ch, INDEX_PINYIN_EN);  
  146.     }  
  147.   
  148.     /** 
  149.      * 返回汉字字符串的拼音(英文字母) 
  150.      *  
  151.      * @param str 
  152.      *            汉字字符串 
  153.      * @return 返回汉字字符串的拼音。将字符串中的汉字替换成拼音,其他字符不变。拼音中间会有空格。 注意,对于多音字,返回的拼音可能不正确。 
  154.      * @throws Exception 
  155.      */  
  156.     public static String GetPinyinEn(String str) throws Exception {  
  157.         StringBuffer sb = new StringBuffer();  
  158.         for (int i = 0; i < str.length(); i++) {  
  159.             char ch = str.charAt(i);  
  160.             if (isChineseChar(ch)) {  
  161.                 sb.append(GetPinyinEn(ch) + " ");  
  162.             } else {  
  163.                 sb.append(ch);  
  164.             }  
  165.         }  
  166.   
  167.         return sb.toString().trim();  
  168.     }  
  169.   
  170.     /** 
  171.      * 获取拼音(中文字母) 
  172.      *  
  173.      * @param ch 
  174.      *            单个汉字字符 
  175.      * @return 返回汉字的中文字母拼音。如 "打"->"dǎ"。 
  176.      * @throws Exception 
  177.      */  
  178.     public static String GetPinyinCn(Character ch) throws Exception {  
  179.         return GetCharInfo(ch, INDEX_PINYIN_CN);  
  180.     }  
  181.   
  182.     /** 
  183.      * 返回汉字字符串的拼音(中文字母) 
  184.      *  
  185.      * @param str 
  186.      *            汉字字符串 
  187.      * @return 返回汉字字符串的拼音。将字符串中的汉字替换成拼音,其他字符不变。拼音中间会有空格。 注意,对于多音字,返回的拼音可能不正确。 
  188.      * @throws Exception 
  189.      */  
  190.     public static String GetPinyinCn(String str) throws Exception {  
  191.         StringBuffer sb = new StringBuffer();  
  192.         for (int i = 0; i < str.length(); i++) {  
  193.             char ch = str.charAt(i);  
  194.             if (isChineseChar(ch)) {  
  195.                 sb.append(GetPinyinCn(ch) + " ");  
  196.             } else {  
  197.                 sb.append(ch);  
  198.             }  
  199.         }  
  200.   
  201.         return sb.toString().trim();  
  202.     }  
  203.   
  204.     /** 
  205.      * 返回拼音首字母 
  206.      *  
  207.      * @param ch 
  208.      * @return 
  209.      * @throws Exception 
  210.      */  
  211.     public static String GetFirstLetter(Character ch) throws Exception {  
  212.         if (isChineseChar(ch)) {  
  213.             return GetPinyinEn(ch).substring(01);  
  214.         } else {  
  215.             return "";  
  216.         }  
  217.     }  
  218.   
  219.     /** 
  220.      * 返回汉字字符串拼音首字母,如果不是汉字,会被忽略掉。 
  221.      *  
  222.      * @param str 
  223.      *            汉字字符串 
  224.      * @return 
  225.      * @throws Exception 
  226.      */  
  227.     public static String GetFirstLetter(String str) throws Exception {  
  228.         StringBuffer sb = new StringBuffer();  
  229.         for (int i = 0; i < str.length(); i++) {  
  230.             char ch = str.charAt(i);  
  231.             if (isChineseChar(ch)) {  
  232.                 sb.append(GetFirstLetter(ch));  
  233.             }  
  234.         }  
  235.   
  236.         return sb.toString().trim();  
  237.     }  
  238.   
  239.     /** 
  240.      * 获取汉字部首 
  241.      *  
  242.      * @param ch 
  243.      *            汉字 
  244.      * @return 返回汉字的部首 
  245.      * @throws Exception 
  246.      */  
  247.     public static String GetBushou(Character ch) throws Exception {  
  248.         return GetCharInfo(ch, INDEX_BUSHOU);  
  249.     }  
  250.   
  251.     /** 
  252.      * 获取汉字笔画数目 
  253.      *  
  254.      * @param ch 
  255.      *            汉字 
  256.      * @return 返回汉字的笔画数目 
  257.      * @throws Exception 
  258.      */  
  259.     public static String GetBihua(Character ch) throws Exception {  
  260.         return GetCharInfo(ch, INDEX_BIHUA);  
  261.     }  
  262.   
  263.     /** 
  264.      * 获取汉字笔画顺序 
  265.      *  
  266.      * @param ch 
  267.      *            汉字 
  268.      * @return 返回汉字的笔画顺序 
  269.      * @throws Exception 
  270.      */  
  271.     public static String GetBishun(Character ch) throws Exception {  
  272.         return GetCharInfo(ch, INDEX_BISHUN);  
  273.     }  
  274.   
  275.     /** 
  276.      * 获取汉字五笔 
  277.      *  
  278.      * @param ch 
  279.      *            汉字 
  280.      * @return 返回汉字五笔 
  281.      * @throws Exception 
  282.      */  
  283.     public static String GetWubi(Character ch) throws Exception {  
  284.         return GetCharInfo(ch, INDEX_WUBI);  
  285.     }  
  286.   
  287.     /** 
  288.      * 获取汉字郑码 
  289.      *  
  290.      * @param ch 
  291.      *            汉字 
  292.      * @return 返回汉字郑码 
  293.      * @throws Exception 
  294.      */  
  295.     public static String GetZhengma(Character ch) throws Exception {  
  296.         return GetCharInfo(ch, INDEX_ZHENGMA);  
  297.     }  
  298.   
  299.     /** 
  300.      * 从字典中获取汉字信息 
  301.      *  
  302.      * @param ch 
  303.      *            要查询的汉字 
  304.      * @return 返回汉字信息,如"25171,打,扌,5,12112,RSH,DAI,da3,dǎ,da2,dá" <br/> 
  305.      *         第一是汉字unicode值<br/> 
  306.      *         第二是汉字<br/> 
  307.      *         第三是汉字部首<br/> 
  308.      *         第四是汉字笔画<br/> 
  309.      *         第五是汉字笔画顺序("12345"分别代表"横竖撇捺折")<br/> 
  310.      *         第六是汉字五笔<br/> 
  311.      *         第七是汉字郑码<br/> 
  312.      *         第八及以后是汉字的拼音(英文字母拼音和中文字母拼音)<br/> 
  313.      * @throws Exception 
  314.      */  
  315.     public static String GetCharInfo(Character ch) throws Exception {  
  316.         if (!isChineseChar(ch)) {  
  317.             throw new Exception("'" + ch + "' 不是一个汉字!");  
  318.         }  
  319.   
  320.         String result = "";  
  321.   
  322.         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);  
  323.         BufferedReader br = new BufferedReader(new InputStreamReader(bais));  
  324.   
  325.         String strWord;  
  326.         while ((strWord = br.readLine()) != null) {  
  327.             if (strWord.startsWith(String.valueOf(ch.hashCode()))) {  
  328.                 result = strWord;  
  329.                 break;  
  330.             }  
  331.         }  
  332.         br.close();  
  333.         bais.close();  
  334.   
  335.         return result;  
  336.     }  
  337.   
  338.     /** 
  339.      * 返回汉字信息 
  340.      *  
  341.      * @param ch 
  342.      *            汉字 
  343.      * @param index 
  344.      *            信息所在的Index 
  345.      * @return 
  346.      * @throws Exception 
  347.      */  
  348.     private static String GetCharInfo(Character ch, int index) throws Exception {  
  349.         if (!isChineseChar(ch)) {  
  350.             throw new Exception("'" + ch + "' 不是一个汉字!");  
  351.         }  
  352.   
  353.         // 获取汉字信息  
  354.         String charInfo = GetCharInfo(ch);  
  355.   
  356.         String result = "";  
  357.         try {  
  358.             result = charInfo.split(",")[index];  
  359.         } catch (Exception e) {  
  360.             throw new Exception("请查看字典中" + ch + "汉字记录是否正确!");  
  361.         }  
  362.   
  363.         return result;  
  364.     }  
  365.   
  366.     /** 
  367.      * 载入字典文件到内存。 
  368.      * @throws Exception  
  369.      */  
  370.     private static void LoadDictionary() throws Exception {  
  371.         File file = new File(DIC_FILENAME);  
  372.         bytes = new byte[(int) file.length()];  
  373.         FileInputStream fis = new FileInputStream(file);  
  374.         fis.read(bytes, 0, bytes.length);  
  375.         fis.close();  
  376.     }  
  377.   
  378.     /** 
  379.      * 判断字符是否为汉字,在测试的时候,我发现汉字的字符的hashcode值 跟汉字Unicode 
  380.      * 16的值一样,所以可以用hashcode来判断是否为汉字。 
  381.      *  
  382.      * @param ch 
  383.      *            汉字 
  384.      * @return 是汉字返回true,否则返回false。 
  385.      */  
  386.     public static boolean isChineseChar(Character ch) {  
  387.         if (ch.hashCode() >= CN_U16_CODE_MIN  
  388.                 && ch.hashCode() <= CN_U16_CODE_MAX) {  
  389.             return true;  
  390.         } else {  
  391.             return false;  
  392.         }  
  393.     }  
  394.   
  395.     /** 
  396.      *  
  397.      * @return 返回字典包含的汉字数目。 
  398.      * @throws Exception 
  399.      */  
  400.     private static int count() throws Exception {  
  401.         int cnt = 0;  
  402.         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);  
  403.         BufferedReader br = new BufferedReader(new InputStreamReader(bais));  
  404.   
  405.         while (br.readLine() != null) {  
  406.             cnt++;  
  407.         }  
  408.         br.close();  
  409.         bais.close();  
  410.   
  411.         return cnt;  
  412.     }  
  413. }  

3.Sample.java

如何使用字典

[java] view plain copy
  1. package com.siqi.dict;  
  2.   
  3. /** 
  4.  * 包含两个实例,示例如何获取汉字的拼音等信息。 
  5.  * @author siqi 
  6.  * 
  7.  */  
  8. public class Sample {  
  9.   
  10.     /** 
  11.      * 字典使用实例 
  12.      *  
  13.      * @param args 
  14.      */  
  15.     public static void main(String[] args) {  
  16.         try {  
  17.             long time = System.currentTimeMillis();  
  18.   
  19.             char ch = '打';  
  20.             //汉字单个字符  
  21.             System.out.println("====打字信息开始====");  
  22.             System.out.println("首字母:"+Dic.GetFirstLetter(ch));  
  23.             System.out.println("拼音(中):"+Dic.GetPinyinCn(ch));  
  24.             System.out.println("拼音(英):"+Dic.GetPinyinEn(ch));  
  25.             System.out.println("部首:"+Dic.GetBushou(ch));  
  26.             System.out.println("笔画数目:"+Dic.GetBihua(ch));  
  27.             System.out.println("笔画:"+Dic.GetBishun(ch));  
  28.             System.out.println("五笔:"+Dic.GetWubi(ch));  
  29.             System.out.println("====打字信息结束====");  
  30.               
  31.             //汉字字符串  
  32.             System.out.println("\r\n====汉字字符串====");  
  33.             System.out.println(Dic.GetPinyinEn("返回汉字字符串的拼音。"));  
  34.             System.out.println(Dic.GetPinyinCn("返回汉字字符串的拼音。"));  
  35.             System.out.println(Dic.GetFirstLetter("返回汉字字符串的拼音。"));  
  36.             System.out.println("====汉字字符串====\r\n");  
  37.               
  38.             System.out.println("用时:"+(System.currentTimeMillis()-time)+"毫秒");  
  39.               
  40.         } catch (Exception e) {  
  41.             e.printStackTrace();  
  42.         }  
  43.   
  44.     }  
  45. }  

4.结果

[html] view plain copy
  1. ====打字信息开始====  
  2. 成功载入字典C:\workspaces\01_java\DictLocal\dic.txt ,用时:15毫秒,载入字符数20902  
  3. 首字母:d  
  4. 拼音(中):dǎ  
  5. 拼音(英):da3  
  6. 部首:扌  
  7. 笔画数目:5  
  8. 笔画:12112  
  9. 五笔:RSH  
  10. ====打字信息结束====  
  11.   
  12. ====汉字字符串====  
  13. fan3 hui2 han4 zi4 zi4 fu2 chuan4 di2 pin1 yin1 。  
  14. fǎn huí hàn zì zì fú chuàn dí pīn yīn 。  
  15. fhhzzfcdpy  
  16. ====汉字字符串====  
  17.   
  18. Memory(Used/Total) : 1539/15872 KB  
  19. 用时: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
  1. package com.siqi.http;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.net.Socket;  
  6. import java.net.URLEncoder;  
  7. import java.util.regex.Matcher;  
  8. import java.util.regex.Pattern;  
  9.   
  10. /** 
  11.  * 使用SOCKET实现简单的网页GET和POST 
  12.  *  
  13.  * @author siqi 
  14.  *  
  15.  */  
  16. public class Httpclient {  
  17.   
  18.     /** 
  19.      * processUrl 参数 HTTP GET 
  20.      */  
  21.     public static final int METHOD_GET = 0;  
  22.     /** 
  23.      * processUrl 参数 HTTP POST 
  24.      */  
  25.     public static final int METHOD_POST = 1;  
  26.     /** 
  27.      * HTTP GET的报头,简化版 
  28.      */  
  29.     public static final String HEADER_GET = "GET %s HTTP/1.0\r\nHOST: %s\r\n\r\n";  
  30.     /** 
  31.      * HTTP POST的报头,简化版 
  32.      */  
  33.     public static final String HEADER_POST = "POST %s HTTP/1.0\r\nHOST: %s\r\nContent-Length: 0\r\n\r\n";  
  34.     /** 
  35.      * 网页报头和内容的分割符 
  36.      */  
  37.     public static final String CONTENT_SEPARATOR = "\r\n\r\n";  
  38.     /** 
  39.      * 网页请求响应内容byte 
  40.      */  
  41.     private byte[] bytes = new byte[0];  
  42.     /** 
  43.      * 网页报头 
  44.      */  
  45.     private String header = "";  
  46.     /** 
  47.      * 网页内容 
  48.      */  
  49.     private String content = "";  
  50.   
  51.     /** 
  52.      * 网页编码,默认为UTF-8 
  53.      */  
  54.     public static final String CHARSET_DEFAULT = "UTF-8";  
  55.     /** 
  56.      * 网页编码 
  57.      */  
  58.     private String charset = CHARSET_DEFAULT;  
  59.   
  60.     /** 
  61.      * 使用Httpclient的例子 
  62.      *  
  63.      * @param args 
  64.      * @throws Exception 
  65.      */  
  66.     public static void main(String[] args) throws Exception {  
  67.         Httpclient httpclient = new Httpclient();  
  68.         // 请求百度首页(手机版)  
  69.         httpclient.processUrl("http://m.baidu.com/");  
  70.         System.out.println("获取网页http://m.baidu.com/");  
  71.         System.out.println("报头为:\r\n" + httpclient.getHeader());  
  72.         System.out.println("内容为:\r\n" + httpclient.getContent());  
  73.         System.out.println("编码为:\r\n" + httpclient.getCharset());  
  74.         System.out.println("************************************");  
  75.   
  76.         // 使用百度搜索"中国"(手机版)  
  77.         // 这是手机百度搜索框的源码 <input id="word" type="text" size="20" maxlength="64"  
  78.         // name="word">  
  79.         String url = String.format("http://m.baidu.com/s?word=%s",  
  80.                 URLEncoder.encode("中国", CHARSET_DEFAULT));  
  81.         httpclient.processUrl(url, METHOD_POST);  
  82.         System.out.println("获取网页http://m.baidu.com/s?word=中国");  
  83.         System.out.println("报头为:\r\n" + httpclient.getHeader());  
  84.         System.out.println("内容为:\r\n" + httpclient.getContent());  
  85.         System.out.println("编码为:\r\n" + httpclient.getCharset());  
  86.     }  
  87.   
  88.     /** 
  89.      * 初始化,设置所有变量为默认值 
  90.      */  
  91.     private void init() {  
  92.         this.bytes = new byte[0];  
  93.         this.charset = CHARSET_DEFAULT;  
  94.         this.header = "";  
  95.         this.content = "";  
  96.   
  97.     }  
  98.   
  99.     /** 
  100.      * 获取网页报头header 
  101.      *  
  102.      * @return 
  103.      */  
  104.     public String getHeader() {  
  105.         return header;  
  106.     }  
  107.   
  108.     /** 
  109.      * 获取网页内容content 
  110.      *  
  111.      * @return 
  112.      */  
  113.     public String getContent() {  
  114.         return content;  
  115.     }  
  116.   
  117.     /** 
  118.      * 获取网页编码 
  119.      *  
  120.      * @return 
  121.      */  
  122.     public String getCharset() {  
  123.         return charset;  
  124.     }  
  125.   
  126.     /** 
  127.      * 请求网页内容(使用HTTP GET) 
  128.      *  
  129.      * @param url 
  130.      * @throws Exception 
  131.      */  
  132.     public void processUrl(String url) throws Exception {  
  133.         processUrl(url, METHOD_GET);  
  134.     }  
  135.   
  136.     /** 
  137.      * 使用Socket请求(获取)一个网页。<br/> 
  138.      * 例如:<br/> 
  139.      * processUrl("http://www.baidu.com/", METHOD_GET)会获取百度首页;<br/> 
  140.      *  
  141.      * @param url 
  142.      *            这个网页或者网页内容的地址 
  143.      * @param method 
  144.      *            请求网页的方法: METHOD_GET或者METHOD_POST 
  145.      * @throws Exception 
  146.      */  
  147.     public void processUrl(String url, int method) throws Exception {  
  148.   
  149.         init();  
  150.   
  151.         // url = "http://www.zdic.net/search/?c=2&q=%E5%A4%A7";  
  152.         // 规范化链接,当网址为http://www.baidu.com时,将网址变为:http://www.baidu.com/  
  153.         Matcher mat = Pattern.compile("https?://[^/]+").matcher(url);  
  154.         if (mat.find() && mat.group().equals(url)) {  
  155.             url += "/";  
  156.         }  
  157.   
  158.         Socket socket = new Socket(getHostUrl(url), 80); // 设置要连接的服务器地址  
  159.         socket.setSoTimeout(3000); // 设置超时时间为3秒  
  160.   
  161.         String request = null;  
  162.         // 构造请求,详情请参考HTTP协议(RFC2616)  
  163.         if (method == METHOD_POST) {  
  164.             request = String.format(HEADER_POST, getSubUrl(url),  
  165.                     getHostUrl(url));  
  166.         } else {  
  167.             request = String  
  168.                     .format(HEADER_GET, getSubUrl(url), getHostUrl(url));  
  169.         }  
  170.   
  171.         socket.getOutputStream().write(request.getBytes());// 发送请求  
  172.   
  173.         this.bytes = InputStream2ByteArray(socket.getInputStream());// 读取响应  
  174.   
  175.         // 获取网页编码,我们只需要测试查找前4096个字节,一般编码信息都会在里面找到  
  176.         String temp = new String(this.bytes, 0,  
  177.                 bytes.length < 4096 ? bytes.length : 4096);  
  178.         mat = Pattern.compile("(?<=<meta.{0,100}?charset=)[a-z-0-9]*",  
  179.                 Pattern.CASE_INSENSITIVE).matcher(temp);  
  180.         if (mat.find()) {  
  181.             this.charset = mat.group();  
  182.         } else {  
  183.             this.charset = CHARSET_DEFAULT;  
  184.         }  
  185.   
  186.         // 用正确的编码得到网页报头和内容  
  187.         temp = new String(this.bytes, this.charset);  
  188.         int headerEnd = temp.indexOf(CONTENT_SEPARATOR);  
  189.         this.header = temp.substring(0, headerEnd);  
  190.         this.content = temp.substring(headerEnd + CONTENT_SEPARATOR.length(),  
  191.                 temp.length());  
  192.   
  193.         socket.close(); // 关闭socket  
  194.     }  
  195.   
  196.     /** 
  197.      * 根据网址,获取服务器地址<br/> 
  198.      * 例如:<br/> 
  199.      * http://m.weathercn.com/common/province.jsp 
  200.      * <p> 
  201.      * 返回:<br/> 
  202.      * m.weathercn.com 
  203.      *  
  204.      * @param url 
  205.      *            网址 
  206.      * @return 
  207.      */  
  208.     public static String getHostUrl(String url) {  
  209.         String host = "";  
  210.         Matcher mat = Pattern.compile("(?<=https?://).+?(?=/)").matcher(url);  
  211.         if (mat.find()) {  
  212.             host = mat.group();  
  213.         }  
  214.   
  215.         return host;  
  216.     }  
  217.   
  218.     /** 
  219.      * 根据网址,获取网页路径 例如:<br/> 
  220.      * http://m.weathercn.com/common/province.jsp 
  221.      * <p> 
  222.      * 返回:<br/> 
  223.      * /common/province.jsp 
  224.      *  
  225.      * @param url 
  226.      * @return 如果没有获取到网页路径,返回""; 
  227.      */  
  228.     public static String getSubUrl(String url) {  
  229.         String subUrl = "";  
  230.         Matcher mat = Pattern.compile("https?://.+?(?=/)").matcher(url);  
  231.         if (mat.find()) {  
  232.             subUrl = url.substring(mat.group().length());  
  233.         }  
  234.   
  235.         return subUrl;  
  236.     }  
  237.   
  238.     /** 
  239.      * 将b1和b2两个byte数组拼接成一个, 结果=b1+b2 
  240.      *  
  241.      * @param b1 
  242.      * @param b2 
  243.      * @return 
  244.      */  
  245.     public static byte[] ByteArrayCat(byte[] b1, byte[] b2) {  
  246.         byte[] b = new byte[b1.length + b2.length];  
  247.         System.arraycopy(b1, 0, b, 0, b1.length);  
  248.         System.arraycopy(b2, 0, b, b1.length, b2.length);  
  249.         return b;  
  250.     }  
  251.   
  252.     /** 
  253.      * 读取输入流并转为byte数组,不返回字符串, 是因为输入流的编码不确定,错误的编码会造成乱码。 
  254.      *  
  255.      * @param is 
  256.      *            输入流inputstream 
  257.      * @return 字符串 
  258.      * @throws IOException 
  259.      */  
  260.     public static byte[] InputStream2ByteArray(InputStream is)  
  261.             throws IOException {  
  262.         byte[] b = new byte[0];  
  263.         byte[] bb = new byte[4096]; // 缓冲区  
  264.   
  265.         int len = 0;  
  266.         while ((len = is.read(bb)) != -1) {  
  267.             byte[] newb = new byte[b.length + len];  
  268.             System.arraycopy(b, 0, newb, 0, b.length);  
  269.             System.arraycopy(bb, 0, newb, b.length, len);  
  270.             b = newb;  
  271.         }  
  272.   
  273.         return b;  
  274.     }  
  275. }  

DictMain.java

[java] view plain copy
  1. package com.siqi.dict;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileReader;  
  5. import java.io.FileWriter;  
  6. import java.io.IOException;  
  7. import java.util.regex.Matcher;  
  8. import java.util.regex.Pattern;  
  9.   
  10. /** 
  11.  * 从汉典下载汉字网页,并提取拼音信息 
  12.  * @author siqi 
  13.  * 
  14.  */  
  15. public class DictMain {  
  16.     /** 
  17.      * 网页保存路径 
  18.      */  
  19.     public static final String SAVEPATH = "dict/pages/";  
  20.     /** 
  21.      * 下载的汉字网页名称 
  22.      */  
  23.     public static final String FILEPATH = SAVEPATH + "%s.html";  
  24.       
  25.     /** 
  26.      * 字典数据文件名称 
  27.      */  
  28.     public static final String DATA_FILENAME = "data.txt";  
  29.       
  30.     /** 
  31.      * 汉字unicode最小 
  32.      */  
  33.     public static final int UNICODE_MIN = 0x4E00;  
  34.       
  35.     /** 
  36.      * 汉字unicode最大 
  37.      */  
  38.     public static final int UNICODE_MAX = 0x9FFF;  
  39.       
  40.     /** 
  41.      * 准备工作: 
  42.      * 1.从汉典网站下载所有汉字的页面,注意,不要在eclipse中打开保存页面的文件夹, 
  43.      * 因为每个汉字一个页面,总共有20000+个页面,容易卡死eclipse 
  44.      * 2.从汉字页面获取汉字拼音信息,生成data.dat文件 
  45.      * 3.生成的data.dat复制到com.siqi.pinyin下面 
  46.      * 4.可以使用com.siqi.pinyin.PinYin.java了 
  47.      */  
  48.     static{  
  49.         // 下载网页  
  50.         for (int i = UNICODE_MIN; i <= UNICODE_MAX; i++) {  
  51.             // 检查是否已经存在  
  52.             String filePath = String.format(FILEPATH, i); // 文件名  
  53.             File file = new File(filePath);  
  54.             if (!file.exists()) {  
  55.                 new DownloadThread(i).start();  
  56.             }  
  57.         }  
  58.           
  59.         //解析网页,得到拼音信息,并保存到data.dat  
  60.         StringBuffer sb = new StringBuffer();  
  61.         for (int i = UNICODE_MIN; i <= UNICODE_MAX; i++) {  
  62.             String word = new String(Character.toChars(i));  
  63.             String pinyin = getPinYinFromWebpageFile(String.format(FILEPATH, i));  
  64.             String str = String.format("%s,%s,%s\r\n", i,word,pinyin);  
  65.             System.out.print(str);  
  66.             sb.append(str);  
  67.         }  
  68.           
  69.         //保存到data.dat  
  70.         try {  
  71.             FileWriter fw = new FileWriter(DATA_FILENAME);  
  72.             fw.write(sb.toString());  
  73.             fw.close();  
  74.         } catch (IOException e) {  
  75.             e.printStackTrace();  
  76.         }  
  77.           
  78.     }  
  79.       
  80.     public static void main(String[] args){  
  81.           
  82.         System.out.println("All prepared!");  
  83.     }  
  84.       
  85.     /** 
  86.      * 从网页文件获取拼音信息 
  87.      * @param file 
  88.      * @return 
  89.      */  
  90.     private static String getPinYinFromWebpageFile(String file) {  
  91.         try {  
  92.               
  93.             char[] buff = new char[(intnew File(file).length()];  
  94.               
  95.             FileReader reader = new FileReader(file);  
  96.             reader.read(buff);  
  97.             reader.close();  
  98.               
  99.             String content = new String(buff);  
  100.             // spf("yi1")  
  101.             Matcher mat = Pattern.compile("(?<=spf\\(\")[a-z1-4]{0,100}",  
  102.                     Pattern.CASE_INSENSITIVE).matcher(content);  
  103.             if (mat.find()) {  
  104.                 return mat.group();  
  105.             }  
  106.             //<span class="dicpy">cal</span> spf("xin1")  
  107.             mat = Pattern.compile("(?<=class=\"dicpy\">)[a-z1-4]{0,100}",  
  108.                     Pattern.CASE_INSENSITIVE).matcher(content);  
  109.             if (mat.find()) {  
  110.                 return mat.group();  
  111.             }  
  112.         } catch (Exception e) {  
  113.             e.printStackTrace();  
  114.         }  
  115.           
  116.         return "";  
  117.   
  118.     }  
  119. }  

DownloadThread.java

[java] view plain copy
  1. package com.siqi.dict;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileWriter;  
  5. import java.net.URLEncoder;  
  6. import java.util.regex.Matcher;  
  7. import java.util.regex.Pattern;  
  8.   
  9. import com.siqi.http.Httpclient;  
  10.   
  11. /** 
  12.  * 将汉字页面从汉典网站下载下来,存储到本地 
  13.  * http://www.zdic.net/search/?c=2 
  14.  * @author siqi 
  15.  * 
  16.  */  
  17. public class DownloadThread extends Thread{  
  18.       
  19.     /** 
  20.      * 线程最大数目 
  21.      */  
  22.     public static int THREAD_MAX = 10;  
  23.       
  24.     /** 
  25.      * 下载最大重复次数 
  26.      */  
  27.     public static int RETRY_MAX = 5;  
  28.       
  29.     /** 
  30.      * 汉典网站搜索网址 
  31.      */  
  32.     public static String SEARCH_URL = "http://www.zdic.net/search/?q=%s";  
  33.       
  34.     /** 
  35.      * 当前线程数目 
  36.      */  
  37.     private static int threadCnt = 0;  
  38.       
  39.     /** 
  40.      * 当前线程处理汉字的unicode编码 
  41.      */  
  42.     private int unicode = 0;  
  43.       
  44.     /** 
  45.      * 如果PATH文件夹不存在,那么创建它 
  46.      */  
  47.     static{  
  48.         try {  
  49.             File file = new File(DictMain.SAVEPATH);  
  50.             if (!file.exists()) {  
  51.                 file.mkdirs();  
  52.             }  
  53.         } catch (Exception e) {  
  54.   
  55.         }  
  56.     }  
  57.       
  58.     /** 
  59.      * 返回当前线程数量 
  60.      * @param i 修改当前线程数量 threadCnt += i; 
  61.      * @return 返回修改后线程数量 
  62.      */  
  63.     public static synchronized int threadCnt(int i){  
  64.         threadCnt += i;  
  65.         return threadCnt;  
  66.     }  
  67.       
  68.     /** 
  69.      * 下载UNICODE编码为unicode的汉字网页 
  70.      * @param unicode 
  71.      */  
  72.     public DownloadThread(int unicode){  
  73.         //等待,直到当前线程数量小于THREAD_MAX  
  74.         while(threadCnt(0)>THREAD_MAX){  
  75.             try {  
  76.                 Thread.sleep(500);  
  77.             } catch (InterruptedException e) {  
  78.             }  
  79.         }  
  80.           
  81.         threadCnt(1);   //线程数量+1  
  82.         this.unicode = unicode;  
  83.     }  
  84.   
  85.     @Override  
  86.     public void run() {  
  87.         long t1 = System.currentTimeMillis(); // 记录时间  
  88.   
  89.         String filePath = String.format(DictMain.FILEPATH, unicode); // 文件名  
  90.   
  91.         String word = new String(Character.toChars(unicode)); // 将unicode转换为数字  
  92.   
  93.         boolean downloaded = false;  
  94.         int retryCnt = 0// 下载失败重复次数  
  95.         while (!downloaded && retryCnt < RETRY_MAX) {  
  96.             try {  
  97.                 String content = DownloadPage(word);  
  98.                 SaveToFile(filePath, content);  
  99.                 downloaded = true;  
  100.   
  101.                 threadCnt(-1);  
  102.                 System.out.println(String.format("%s, %s, 下载成功!线程数目:%s 用时:%s",  
  103.                         unicode, word, threadCnt(0), System.currentTimeMillis()  
  104.                                 - t1));  
  105.                 return;  
  106.             } catch (Exception e) {  
  107.                 retryCnt++;  
  108.             }  
  109.         }  
  110.   
  111.         threadCnt(-1);  
  112.         System.err.println(String.format("%s, %s, 下载失败!线程数目:%s 用时:%s", unicode,  
  113.                 word, threadCnt(0), System.currentTimeMillis() - t1));  
  114.     }  
  115.       
  116.     /** 
  117.      * 在汉典网站上查找汉字,返回汉字字典页面内容 
  118.      * @param word 
  119.      * @return 
  120.      * @throws Exception 
  121.      */  
  122.     public String DownloadPage(String word) throws Exception{  
  123.         //查找word  
  124.         Httpclient httpclient = new Httpclient();  
  125.         String url = String.format(SEARCH_URL, URLEncoder.encode(word, "UTF-8"));  
  126.         httpclient.processUrl(url, Httpclient.METHOD_POST);  
  127.           
  128.         //返回的是一个跳转页  
  129.         //获取跳转的链接  
  130.         Matcher mat = Pattern.compile("(?<=HREF=\")[^\"]+").matcher(httpclient.getContent());  
  131.         if(mat.find()){  
  132.             httpclient.processUrl(mat.group());  
  133.         }  
  134.           
  135.         return httpclient.getContent();  
  136.     }  
  137.       
  138.     /** 
  139.      * 将内容content写入file文件 
  140.      * @param file 
  141.      * @param content 
  142.      */  
  143.     public void SaveToFile(String file, String content){  
  144.         try {  
  145.             FileWriter fw = new FileWriter(file);  
  146.             fw.write(content);  
  147.             fw.close();  
  148.         } catch (Exception e) {  
  149.             e.printStackTrace();  
  150.         }  
  151.     }  
  152. }  

PinYin.java

[java] view plain copy
  1. package com.siqi.pinyin;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.InputStreamReader;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7.   
  8. public class PinYin {  
  9.   
  10.     private static Map<Integer, PinYinEle> map = new HashMap<Integer, PinYinEle>();  
  11.   
  12.     /** 
  13.      * 载入pinyin数据文件 
  14.      */  
  15.     static {  
  16.         try {  
  17.             BufferedReader bReader = new BufferedReader(new InputStreamReader(  
  18.                     PinYin.class.getResourceAsStream("data.dat")));  
  19.             String aLine = null;  
  20.             while ((aLine = bReader.readLine()) != null) {  
  21.                 PinYinEle ele = new PinYinEle(aLine);  
  22.                 map.put(ele.getUnicode(), ele);  
  23.             }  
  24.             bReader.close();  
  25.         } catch (Exception e) {  
  26.             e.printStackTrace();  
  27.         }  
  28.     }  
  29.   
  30.     /** 
  31.      * 去掉注释可以测试一下 
  32.      *  
  33.      * @param args 
  34.      */  
  35.     public static void main(String[] args) {  
  36.         System.out.println(" 包含声调:" + PinYin.getPinYin("大家haome12345"));  
  37.         System.out.println("不包含声调:" + PinYin.getPinYin("大家haome12345"false));  
  38.     }  
  39.   
  40.     /** 
  41.      * 获取汉字字符串的拼音,containsNumber是否获取拼音中的声调1、2、3、4 
  42.      *  
  43.      * @param str 
  44.      * @param containsNumber 
  45.      *            true = 包含声调,false = 不包含声调 
  46.      * @return 
  47.      */  
  48.     public static String getPinYin(String str, boolean containsNumber) {  
  49.         StringBuffer sb = new StringBuffer();  
  50.         for (Character ch : str.toCharArray()) {  
  51.             sb.append(getPinYin(ch, containsNumber));  
  52.         }  
  53.   
  54.         return sb.toString();  
  55.     }  
  56.   
  57.     /** 
  58.      * 获取字符串的拼音 
  59.      *  
  60.      * @param str 
  61.      * @return 
  62.      */  
  63.     public static String getPinYin(String str) {  
  64.         StringBuffer sb = new StringBuffer();  
  65.         for (Character ch : str.toCharArray()) {  
  66.             sb.append(getPinYin(ch));  
  67.         }  
  68.   
  69.         return sb.toString();  
  70.     }  
  71.   
  72.     /** 
  73.      * 获取单个汉字的拼音,包含声调 
  74.      *  
  75.      * @param ch 
  76.      * @return 
  77.      */  
  78.     public static String getPinYin(Character ch) {  
  79.         return getPinYin(ch, true);  
  80.     }  
  81.   
  82.     /** 
  83.      * 获取单个汉字的拼音 
  84.      *  
  85.      * @param ch 
  86.      *            汉字. 如果输入非汉字,返回ch. 如果输入null,返回空字符串; 
  87.      * @param containsNumber 
  88.      *            true = 包含声调,false = 不包含声调 
  89.      * @return 
  90.      */  
  91.     public static String getPinYin(Character ch, boolean containsNumber) {  
  92.         if (ch != null) {  
  93.             int code = ch.hashCode();  
  94.             if (map.containsKey(code)) {  
  95.                 if (containsNumber) {  
  96.                     return map.get(code).getPinyin();  
  97.                 } else {  
  98.                     return map.get(code).getPinyin().replaceAll("[0-9]""");  
  99.                 }  
  100.             } else {  
  101.                 return ch.toString();  
  102.             }  
  103.         }  
  104.         return "";  
  105.     }  
  106. }  


PinYinEle.java

[java] view plain copy
  1. package com.siqi.pinyin;  
  2.   
  3. public class PinYinEle {  
  4.     private int unicode;  
  5.     private String ch;  
  6.     private String pinyin;  
  7.       
  8.     public PinYinEle(){}  
  9.       
  10.     public PinYinEle(String str){  
  11.         if(str!=null){  
  12.             String[] strs = str.split(",");  
  13.             if(strs.length == 3){  
  14.                 try{  
  15.                 this.unicode = Integer.parseInt(strs[0]);  
  16.                 }catch(Exception e){  
  17.                       
  18.                 }  
  19.                 this.ch = strs[1];  
  20.                 this.pinyin = strs[2];  
  21.             }  
  22.         }  
  23.           
  24.     }  
  25.       
  26.     public int getUnicode() {  
  27.         return unicode;  
  28.     }  
  29.     public void setUnicode(int unicode) {  
  30.         this.unicode = unicode;  
  31.     }  
  32.     public String getCh() {  
  33.         return ch;  
  34.     }  
  35.     public void setCh(String ch) {  
  36.         this.ch = ch;  
  37.     }  
  38.     public String getPinyin() {  
  39.         return pinyin;  
  40.     }  
  41.     public void setPinyin(String pinyin) {  
  42.         this.pinyin = pinyin;  
  43.     }  
  44.       
  45.       
  46. }  

生成的data.dat里面内容(部分)为:

[java] view plain copy
  1. 19968,一,yi1  
  2. 19969,丁,ding1  
  3. 19970,丂,kao3  
  4. 19971,七,qi1  
  5. 19972,丄,shang4  
  6. 19973,丅,xia4  
  7. 19974,丆,han3  
  8. 19975,万,wan4  
  9. 19976,丈,zhang4  
  10. 19977,三,san1  
  11. 19978,上,shang4  
  12. 19979,下,xia4  
  13. 19980,丌,qi2  
  14. 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
  1. 包含声调:da4jia1haome12345  
  2. 包含声调:dajiahaome12345  



上面只是显示了如何获取拼音,获取笔画等的方法类似,在这里就不演示了。

1 0
原创粉丝点击