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

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

2018-12-15 22:00

文档管理软件,文档管理系统,知识管理系统,档案管理系统的技术资料:

一、词库

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

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

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

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

二、设计思路

算法简要描述:

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

数据结构:

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

三、程序

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

[code]
csharp
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;
}
}
[/code]

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

然后就有实用价值了.