区别与英文句子,子串,中文汉字之间并没有空格相隔开,所以对于一个汉语的句子来说,如何分词一直也有人在研究,现也有多种根据句子结构,根据词频概率的多种做法,之前因为项目需求需要用到一个中文分词的功能,鉴于时间和功力,就跟网上找了张华平博士的NLPIR中文分词系统,一段时间用还好,可是过段时间之后就完全用不了,错误日志说是因为线程问题,(线程跟时间应该没有关系吧,大概是版权什么的),之后又找了一下编译了一下friso的库文件,但是由于字典文件的路径问题(大神是这么说的),初始化不对,导致分词有误,遂决定自己尝试一下mmseg。
附参考前辈的博文地址 http://blog.csdn.net/sunlylorn/article/details/7652746
大致思路:
首先利用hash_map 构造一个字典 hash_map<WCHAR,vector<BSTR>>,其中vector容器中存放相同词首的词语PS:中国、中国人、中间.blabla....
构造完字典之后根据mmseg的做法
1:首先查找以当前句首词开始的所有的三词chunks
2:根据以下4个规则依次进行筛选
规则1:最大匹配
规则2:最大平均单词长度
规则3:单词长度最小方差
规则4:最大单字单词语素自由度之和
因为涉及词频的查询,最后一步未完成,个人以为,整个算法最关键的地方在于1、词典的构造,词典的大小很大程度决定分词的正确率,2:如何查找以当前句首单词开始的所有chunks这里我用了一个嵌套循环的函数,找到以当前句首开始的所有三词chunks,暂时没有考虑这个词已经是句尾的情况。DicHashmap 就是构造好的汉语字典
void CWSdic::FindAllTrunks(BSTR str,DicHashmap& dichashmap)
{
int Count=FindWordsCount(str,dichashmap);//获取到以当前句首词开始的最大词长,
for(int i=1;i <= Count; i++)
{
Chunk newchunk;//new 一个新的chunk
newchunk.push_back( GetBstrByCount(str,i));
BSTR str1=str;
// str1.Delete(0,i+1);
DeleteNCount(str1,i);
int Count1 = FindWordsCount(str1,dichashmap);
for(int j = 1; j<= Count1;j++ )
{
Chunk newchunk1(newchunk);//构造的过程,将chunk的元素复制到里面
// newchunk1.push_back(str1.Left(j));
newchunk1.push_back(GetBstrByCount(str1,j));
BSTR str2 = str1;
// str2.Delete(0,j+2);
DeleteNCount(str2,j);
int Count2 = FindWordsCount(str2,dichashmap);
for(int k=1;k<= Count2;k++)
{
Chunk newchunk2(newchunk1);
// newchunk2.push_back(str2.Left(k));
newchunk2.push_back(GetBstrByCount(str2,k));
ChunkList.push_back(newchunk2);
}
}
}
}
调用过程
BOOL CWSdic::ComflexMaxMatch(DicHashmap& dichashmap,CString ori_str ,vector<CString>& wordvector,int Count)
{
/*
复杂最大匹配:
chen 和liu 认为最大的匹配规则是三个单词:
从句子头部开始,寻找所有三个分词chunks方案。
从一个既定的字符开始,匹配出所有的三个词为一组
的组合。
使用中用四个消除歧义规则,进行过滤直到只存在一种结果
或者四个规则使用完毕。
1、最大匹配:
有两种方案:
简单最大匹配:选择长度最大的词
复杂匹配:选择词组长度最大的那个词组
2、最大平均词语长度:
经过规则1后剩余的词组个数超过1,就选择平均词组长度最大的一个
3、词语长度的最小变化率
词语长度变化率可以由标准差反映,直接套用标准差公式.
标准差=sqrt((x1-x)^2+(x2-x)^2+(x3-x))/3
4、largest sum of degree of mor...涉及统计词频,暂时不考虑
*/
//BSTR bstr1 = function(ori_str);
//int bstr1_len = SysStringLen(bstr1);
BSTR bstr = ori_str.AllocSysString();
//step 1:获取所有的chunks
FindAllTrunks(bstr,dichashmap);
if(ChunkList.size()>1)
{
//step 2:找到所有chunks里面长度最大的若干个.
GetMaxLenChunks();
if(ChunkList.size()>1)
{
//step 3:利用平均长度
MaximumAvargeLength(ChunkList);
if(ChunkList.size()>1)
{
//step 4:利用方差
MinimumVariance(ChunkList);
if(ChunkList.size()>1)
{
//step 5:利用词频
}
}
}
}
return TRUE;
}
自己构造的一个chunk类
class Chunk
{
public:
Chunk();
Chunk(const Chunk& chunk);
~Chunk();
public:
vector<BSTR> m_chunk;
int m_MaxLength;
float m_MiniVariance;
float m_maxavarlen ;
public:
void push_back(BSTR str);
};