简单实用的C#分词源代码(含词库素材下载)

一、词库 

词库大概有5万多词语(Google能搜到,类似的词库都能用),我摘要如下: 

地区 82 
重要 81 
新华社 80 
技术 80 
会议 80 
自己 79 
干部 78 
职工 78 
群众 77 
没有 77 
今天 76 
同志 76 
部门 75 
加强 75 
组织 75 

点击下面链接下载中文词库素材(纯文本文件) 
http://www.legalsoft.com.cn/download/cndict.rar 

第一列是词,第二列是权重.我写的这个分词算法目前并未利用权重. 

二、设计思路 

算法简要描述: 

对一个字符串S,从前到后扫描,对扫描的每个字,从词库中寻找最长匹配.比如假设S="我是中华人民共和国公民",词库中有"中华人民共和国","中华","公民","人民","共和国"......等词.当扫描到"中"字,那么从中字开始,向后分别取1,2,3,......个字("中","中华","中华人","中华人民","中华人民共","中华人民共和","中华人民共和国",,"中华人民共和国公"),词库中的最长匹配字符串是"中华人民共和国",那么就此切分开,扫描器推进到"公"字. 

数据结构: 

选择什么样的数据结构对性能影响很大.我采用Hashtable _rootTable记录词库.键值对为(键,插入次数).对每一个词语,如果该词语有N个字,则将该词语的1,1~2,1~3,......1~N个字作为键,插入_rootTable中.而同一个键如果重复插入,则后面的值递增. 

三、程序 

具体程序如下(程序中包含权重,插入次数等要素,目前的算法并没有利用这些.可以借此写出更有效的分词算法): 

  1. public struct ChineseWordUnit  
  2. {  
  3.     private string _word;  
  4.     private int _power;  
  5.     /// <summary>  
  6.     /// 中文词语单元所对应的中文词。  
  7.     /// </summary>  
  8.     public string Word  
  9.     {  
  10.         get  
  11.         {  
  12.             return _word;  
  13.         }  
  14.     }  
  15.     /// <summary>  
  16.     /// 该中文词语的权重。  
  17.     /// </summary>  
  18.     public int Power  
  19.     {  
  20.         get  
  21.         {  
  22.             return _power;  
  23.         }  
  24.     }  
  25.     /// <summary>  
  26.     /// 结构初始化。  
  27.     /// </summary>  
  28.     /// <param name="word">中文词语</param>  
  29.     /// <param name="power">该词语的权重</param>  
  30.     public ChineseWordUnit(string word, int power)  
  31.     {  
  32.         this._word = word;  
  33.         this._power = power;  
  34.     }  
  35. }  
  36. /// <summary>  
  37. /// 记录字符串出现在中文字典所录中文词语的前端的次数的字典类。如字符串"中"出现在"中国"的前端,则在字典中记录一个次数。  
  38. /// </summary>  
  39. public class ChineseWordsHashCountSet  
  40. {  
  41.     /// <summary>  
  42.     /// 记录字符串在中文词语中出现次数的Hashtable。键为特定的字符串,值为该字符串在中文词语中出现的次数。  
  43.     /// </summary>  
  44.     private Hashtable _rootTable;  
  45.     /// <summary>  
  46.     /// 类型初始化。  
  47.     /// </summary>  
  48.     public ChineseWordsHashCountSet()  
  49.     {  
  50.         _rootTable = new Hashtable();  
  51.     }  
  52.     /// <summary>  
  53.     /// 查询指定字符串出现在中文字典所录中文词语的前端的次数。  
  54.     /// </summary>  
  55.     /// <param name="s">指定字符串</param>  
  56.     /// <returns>字符串出现在中文字典所录中文词语的前端的次数。若为-1,表示不出现。</returns>  
  57.     public int GetCount(string s)  
  58.     {  
  59.         if (!this._rootTable.ContainsKey(s.Length))  
  60.         {  
  61.             return -1;  
  62.         }  
  63.         Hashtable _tempTable = (Hashtable)this._rootTable[s.Length];  
  64.         if (!_tempTable.ContainsKey(s))  
  65.         {  
  66.             return -1;  
  67.         }  
  68.         return (int)_tempTable[s];  
  69.     }  
  70.     /// <summary>  
  71.     /// 向次数字典中插入一个词语。解析该词语,插入次数字典。  
  72.     /// </summary>  
  73.     /// <param name="s">所处理的字符串。</param>  
  74.     public void InsertWord(string s)  
  75.     {  
  76.         for (int i = 0; i < s.Length; i++)  
  77.         {  
  78.             string _s = s.Substring(0, i + 1);  
  79.             this.InsertSubString(_s);  
  80.         }  
  81.     }  
  82.    /// <summary>  
  83.     /// 向次数字典中插入一个字符串的次数记录。  
  84.     /// </summary>  
  85.     /// <param name="s">所插入的字符串。</param>  
  86.     private void InsertSubString(string s)  
  87.     {  
  88.         if (!_rootTable.ContainsKey(s.Length) && s.Length > 0)  
  89.         {  
  90.             Hashtable _newHashtable = new Hashtable();  
  91.             _rootTable.Add(s.Length, _newHashtable);  
  92.         }  
  93.         Hashtable _tempTable = (Hashtable)_rootTable[s.Length];  
  94.         if (!_tempTable.ContainsKey(s))  
  95.         {  
  96.             _tempTable.Add(s, 1);  
  97.         }  
  98.         else  
  99.         {  
  100.             _tempTable[s] = (int)_tempTable[s] + 1;  
  101.         }  
  102.     }  
  103. }  
  104. /// <summary>  
  105. /// 中文分词器。  
  106. /// </summary>  
  107. public class ChineseParse  
  108. {  
  109.     private static ChineseWordsHashCountSet _countTable;  
  110.     static ChineseParse()  
  111.     {  
  112.         _countTable = new ChineseWordsHashCountSet();  
  113.         InitFromFile("ChineseDictionary.txt");  
  114.     }  
  115.     /// <summary>  
  116.     /// 从指定的文件中初始化中文词语字典和字符串次数字典。  
  117.     /// </summary>  
  118.     /// <param name="fileName">文件名</param>  
  119.     private static void InitFromFile(string fileName)  
  120.     {  
  121.         string path = Directory.GetCurrentDirectory() + @"\" + fileName;  
  122.         if (File.Exists(path))  
  123.         {  
  124.             using (StreamReader sr = File.OpenText(path))  
  125.             {  
  126.                 string s = "";  
  127.                 while ((s = sr.ReadLine()) != null)  
  128.                 {  
  129.                     ChineseWordUnit _tempUnit = InitUnit(s);  
  130.                     _countTable.InsertWord(_tempUnit.Word);  
  131.                 }  
  132.             }  
  133.         }  
  134.     }  
  135.     /// <summary>  
  136.     /// 将一个字符串解析为ChineseWordUnit。  
  137.     /// </summary>  
  138.     /// <param name="s">字符串</param>  
  139.     /// <returns>解析得到的ChineseWordUnit<40          
  140.     private static ChineseWordUnit InitUnit(string s)  
  141.     {  
  142.         Regex reg = new Regex(@"\s+");  
  143.         string[] temp = reg.Split(s);  
  144.         if (temp.Length != 2)  
  145.         {  
  146.             throw new Exception("字符串解析错误:" + s);  
  147.         }  
  148.         return new ChineseWordUnit(temp[0], Int32.Parse(temp[1]));  
  149.     }  
  150.     /// <summary>  
  151.     /// 分析输入的字符串,将其切割成一个个的词语。  
  152.     /// </summary>  
  153.     /// <param name="s">待切割的字符串</param>  
  154.     /// <returns>所切割得到的中文词语数组</returns>  
  155.     public static string[] ParseChinese(string s)  
  156.     {  
  157.         int _length = s.Length;  
  158.         string _temp = String.Empty;  
  159.         ArrayList _words = new ArrayList();  
  160.         for (int i = 0; i < s.Length; )  
  161.         {  
  162.             _temp = s.Substring(i, 1);  
  163.             if (_countTable.GetCount(_temp) > 1)  
  164.             {  
  165.                 int j = 2;  
  166.                 for (; i + j < s.Length + 1 && _countTable.GetCount(s.Substring(i, j)) > 0; j++)  
  167.                 {  
  168.                 }  
  169.                 _temp = s.Substring(i, j - 1);  
  170.                 i = i + j - 2;  
  171.             }  
  172.             i++;  
  173.             _words.Add(_temp);  
  174.         }  
  175.         string[] _tempStringArray = new string[_words.Count];  
  176.         _words.CopyTo(_tempStringArray);  
  177.         return _tempStringArray;  
  178.     }  
  179. }  

进一步应该做的: 
1,能识别简单的外语,数字 
2,具备简单智能 
3,扩充词库 

然后就有实用价值了. 
posted @ 2011-03-08 10:31  与时俱进  阅读(2560)  评论(0编辑  收藏  举报
友情链接:同里老宅院民居客栈