几个月之前,在网上找到了一个中文词库素材(几百K),当时便想写一个分词程序了.我对汉语分词没有什么研究,也就凭自己臆想而写.若有相关方面专家,还请多给意见.
一、词库
词库大概有5万多词语(google能搜到,类似的词库都能用),我摘要如下:
地区82
重要81
新华社80
技术80
会议80
自己79
干部78
职工78
群众77
没有77
今天76
同志76
部门75
加强75
组织75
第一列是词,第二列是权重.我写的这个分词算法目前并未利用权重.
二、设计思路
算法简要描述:
对一个字符串S,从前到后扫描,对扫描的每个字,从词库中寻找最长匹配.比如假设S="我是中华人民共和国公民",词库中有"中华人民共和国","中华","公民","人民","共和国"......等词.当扫描到"中"字,那么从中字开始,向后分别取1,2,3,......个字("中","中华","中华人","中华人民","中华人民共","中华人民共和","中华人民共和国",,"中华人民共和国公"),词库中的最长匹配字符串是"中华人民共和国",那么就此切分开,扫描器推进到"公"字.
数据结构:
选择什么样的数据结构对性能影响很大.我采用Hashtable _rootTable记录词库.键值对为(键,插入次数).对每一个词语,如果该词语有N个字,则将该词语的1,1~2,1~3,......1~N个字作为键,插入_rootTable中.而同一个键如果重复插入,则后面的值递增.
三、程序
具体程序如下(程序中包含权重,插入次数等要素,目前的算法并没有利用这些.可以借此写出更有效的分词算法):
ChineseWordUnit.cs //struct--(词语,权重)对
1
publicstructChineseWordUnit
2

{
3
privatestring_word;
4
privateint_power;
5
6
/**////<summary>
7
///中文词语单元所对应的中文词。
8
///</summary>
9
publicstringWord
10

{
11
get
12

{
13
return_word;
14
}
15
}
16
17
/**////<summary>
18
///该中文词语的权重。
19
///</summary>
20
publicintPower
21

{
22
get
23

{
24
return_power;
25
}
26
}
27
28
/**////<summary>
29
///结构初始化。
30
///</summary>
31
///<paramname="word">中文词语</param>
32
///<paramname="power">该词语的权重</param>
33
publicChineseWordUnit(stringword,intpower)
34

{
35
this._word=word;
36
this._power=power;
37
}
38
}
ChineseWordsHashCountSet.cs //词库容器
1
/**////<summary>
2
///记录字符串出现在中文字典所录中文词语的前端的次数的字典类。如字符串“中”出现在“中国”的前端,则在字典中记录一个次数。
3
///</summary>4
publicclassChineseWordsHashCountSet
5

{
6
/**////<summary>
7
///记录字符串在中文词语中出现次数的Hashtable。键为特定的字符串,值为该字符串在中文词语中出现的次数。
8
///</summary>
9
privateHashtable_rootTable;
10
11
/**////<summary>
12
///类型初始化。
13
///</summary>
14
publicChineseWordsHashCountSet()
15

{
16
_rootTable=newHashtable();
17
}
18
19
/**////<summary>
20
///查询指定字符串出现在中文字典所录中文词语的前端的次数。
21
///</summary>
22
///<paramname="s">指定字符串</param>
23
///<returns>字符串出现在中文字典所录中文词语的前端的次数。若为-1,表示不出现。</returns>
24
publicintGetCount(strings)
25

{
26
if(!this._rootTable.ContainsKey(s.Length))
27

{
28
return-1;
29
}
30
Hashtable_tempTable=(Hashtable)this._rootTable[s.Length];
31
if(!_tempTable.ContainsKey(s))
32

{
33
return-1;
34
}
35
return(int)_tempTable[s];
36
}
37
38
/**////<summary>
39
///向次数字典中插入一个词语。解析该词语,插入次数字典。
40
///</summary>
41
///<paramname="s">所处理的字符串。</param>
42
publicvoidInsertWord(strings)
43

{
44
for(inti=0;i<s.Length;i++)
45

{
46
string_s=s.Substring(0,i+1);
47
this.InsertSubString(_s);
48
}
49
}
50
51
/**////<summary>
52
///向次数字典中插入一个字符串的次数记录。
53
///</summary>
54
///<paramname="s">所插入的字符串。</param>
55
privatevoidInsertSubString(strings)
56

{
57
if(!_rootTable.ContainsKey(s.Length)&&s.Length>0)
58

{
59
Hashtable_newHashtable=newHashtable();
60
_rootTable.Add(s.Length,_newHashtable);
61
}
62
Hashtable_tempTable=(Hashtable)_rootTable[s.Length];
63
if(!_tempTable.ContainsKey(s))
64

{
65
_tempTable.Add(s,1);
66
}
67
else
68

{
69
_tempTable[s]=(int)_tempTable[s]+1;
70
}
71
}
72
}
ChineseParse.cs //分词器
1
/**////<summary>
2
///中文分词器。
3
///</summary>4
publicclassChineseParse
5

{
6
privatestaticChineseWordsHashCountSet_countTable;
7
8
staticChineseParse()
9

{
10
_countTable=newChineseWordsHashCountSet();
11
InitFromFile("ChineseDictionary.txt");
12
}
13
14
/**////<summary>
15
///从指定的文件中初始化中文词语字典和字符串次数字典。
16
///</summary>
17
///<paramname="fileName">文件名</param>
18
privatestaticvoidInitFromFile(stringfileName)
19

{
20
stringpath=Directory.GetCurrentDirectory()+@"\"+fileName;
21
if(File.Exists(path))
22

{
23
using(StreamReadersr=File.OpenText(path))
24

{
25
strings="";
26
while((s=sr.ReadLine())!=null)
27

{
28
ChineseWordUnit_tempUnit=InitUnit(s);
29
_countTable.InsertWord(_tempUnit.Word);
30
}
31
}