简单实用的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,能识别简单的外语,数字
2,具备简单智能
3,扩充词库
然后就有实用价值了.
词库大概有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中.而同一个键如果重复插入,则后面的值递增.
三、程序
具体程序如下(程序中包含权重,插入次数等要素,目前的算法并没有利用这些.可以借此写出更有效的分词算法):
- public struct ChineseWordUnit
- {
- private string _word;
- private int _power;
- /// <summary>
- /// 中文词语单元所对应的中文词。
- /// </summary>
- public string Word
- {
- get
- {
- return _word;
- }
- }
- /// <summary>
- /// 该中文词语的权重。
- /// </summary>
- public int Power
- {
- get
- {
- return _power;
- }
- }
- /// <summary>
- /// 结构初始化。
- /// </summary>
- /// <param name="word">中文词语</param>
- /// <param name="power">该词语的权重</param>
- public ChineseWordUnit(string word, int power)
- {
- this._word = word;
- this._power = power;
- }
- }
- /// <summary>
- /// 记录字符串出现在中文字典所录中文词语的前端的次数的字典类。如字符串"中"出现在"中国"的前端,则在字典中记录一个次数。
- /// </summary>
- public class ChineseWordsHashCountSet
- {
- /// <summary>
- /// 记录字符串在中文词语中出现次数的Hashtable。键为特定的字符串,值为该字符串在中文词语中出现的次数。
- /// </summary>
- private Hashtable _rootTable;
- /// <summary>
- /// 类型初始化。
- /// </summary>
- public ChineseWordsHashCountSet()
- {
- _rootTable = new Hashtable();
- }
- /// <summary>
- /// 查询指定字符串出现在中文字典所录中文词语的前端的次数。
- /// </summary>
- /// <param name="s">指定字符串</param>
- /// <returns>字符串出现在中文字典所录中文词语的前端的次数。若为-1,表示不出现。</returns>
- public int GetCount(string s)
- {
- if (!this._rootTable.ContainsKey(s.Length))
- {
- return -1;
- }
- Hashtable _tempTable = (Hashtable)this._rootTable[s.Length];
- if (!_tempTable.ContainsKey(s))
- {
- return -1;
- }
- return (int)_tempTable[s];
- }
- /// <summary>
- /// 向次数字典中插入一个词语。解析该词语,插入次数字典。
- /// </summary>
- /// <param name="s">所处理的字符串。</param>
- public void InsertWord(string s)
- {
- for (int i = 0; i < s.Length; i++)
- {
- string _s = s.Substring(0, i + 1);
- this.InsertSubString(_s);
- }
- }
- /// <summary>
- /// 向次数字典中插入一个字符串的次数记录。
- /// </summary>
- /// <param name="s">所插入的字符串。</param>
- private void InsertSubString(string s)
- {
- if (!_rootTable.ContainsKey(s.Length) && s.Length > 0)
- {
- Hashtable _newHashtable = new Hashtable();
- _rootTable.Add(s.Length, _newHashtable);
- }
- Hashtable _tempTable = (Hashtable)_rootTable[s.Length];
- if (!_tempTable.ContainsKey(s))
- {
- _tempTable.Add(s, 1);
- }
- else
- {
- _tempTable[s] = (int)_tempTable[s] + 1;
- }
- }
- }
- /// <summary>
- /// 中文分词器。
- /// </summary>
- public class ChineseParse
- {
- private static ChineseWordsHashCountSet _countTable;
- static ChineseParse()
- {
- _countTable = new ChineseWordsHashCountSet();
- InitFromFile("ChineseDictionary.txt");
- }
- /// <summary>
- /// 从指定的文件中初始化中文词语字典和字符串次数字典。
- /// </summary>
- /// <param name="fileName">文件名</param>
- private static void InitFromFile(string fileName)
- {
- string path = Directory.GetCurrentDirectory() + @"\" + fileName;
- if (File.Exists(path))
- {
- using (StreamReader sr = File.OpenText(path))
- {
- string s = "";
- while ((s = sr.ReadLine()) != null)
- {
- ChineseWordUnit _tempUnit = InitUnit(s);
- _countTable.InsertWord(_tempUnit.Word);
- }
- }
- }
- }
- /// <summary>
- /// 将一个字符串解析为ChineseWordUnit。
- /// </summary>
- /// <param name="s">字符串</param>
- /// <returns>解析得到的ChineseWordUnit<40
- private static ChineseWordUnit InitUnit(string s)
- {
- Regex reg = new Regex(@"\s+");
- string[] temp = reg.Split(s);
- if (temp.Length != 2)
- {
- throw new Exception("字符串解析错误:" + s);
- }
- return new ChineseWordUnit(temp[0], Int32.Parse(temp[1]));
- }
- /// <summary>
- /// 分析输入的字符串,将其切割成一个个的词语。
- /// </summary>
- /// <param name="s">待切割的字符串</param>
- /// <returns>所切割得到的中文词语数组</returns>
- public static string[] ParseChinese(string s)
- {
- int _length = s.Length;
- string _temp = String.Empty;
- ArrayList _words = new ArrayList();
- for (int i = 0; i < s.Length; )
- {
- _temp = s.Substring(i, 1);
- if (_countTable.GetCount(_temp) > 1)
- {
- int j = 2;
- for (; i + j < s.Length + 1 && _countTable.GetCount(s.Substring(i, j)) > 0; j++)
- {
- }
- _temp = s.Substring(i, j - 1);
- i = i + j - 2;
- }
- i++;
- _words.Add(_temp);
- }
- string[] _tempStringArray = new string[_words.Count];
- _words.CopyTo(_tempStringArray);
- return _tempStringArray;
- }
- }
进一步应该做的:
1,能识别简单的外语,数字
2,具备简单智能
3,扩充词库
然后就有实用价值了.