一、词库
词库大概有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中.而同一个键如果重复插入,则后面的值递增.
三、程序
具体程序如下(程序中包含权重,插入次数等要素,目前的算法并没有利用这些.可以借此写出更有效的分词算法):
> 纯文本方式> 拷贝到裁剪板> 打印
01.public struct ChineseWordUnit
02.{
03. private string _word;
04. private int _power;
05. /// <summary>
06. /// 中文词语单元所对应的中文词。
07. /// </summary>
08. public string Word
09. {
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,扩充词库
然后就有实用价值了.