标签:
这两种分词方法都是机械分词方法,按照一定的策略将待分析的汉字串与机器词典中的词条进行匹配,若在词典中找到某个字符串,则匹配成功。按照扫描方向的不同,串匹配分词方法可以分为正向匹配和逆向匹配。按照不同长度优先匹配的情况,可以分为最大匹配和最小匹配。由于汉语单字成词的特点,正向最小匹配和逆向最小匹配一般很少用。一般说来,逆向匹配的切分精度略高于正向匹配,遇到的歧义现象也较少。统计结果表明,单纯使用正向最大匹配的错误率为1/169,单纯使用逆向最大匹配的错误率为1/245。但这种精度还远远不能满足实际的需要。实际使用的分词系统,都是把机械分词作为一种初分手段,还需通过利用各种其它的语言信息来进一步提高切分的准确率。
例:今天来了许多新同事
1.正向最大匹配算法,规定最大匹配长度为5
今天来了许
今天来了
今天来
今天====》得到一个词–今天
来了许多新
来了许多
来了许
来了
来====》得到一个词–来
了许多新同
了许多新
了许多
了许
了====》得到一个词–了
许多新同事
许多新同
许多新
许多====》得到一个词–许多
新同事
新同
新====》得到一个词–新
同事====》得到一个词–同事
最后正向最大匹配的结果是:/今天/来/了/许多/新/同事/
2.逆向最大匹配算法,规定最大匹配长度为5
许多新同事
多新同事
新同事
同事====》得到一个词–同事
来了许多新
了许多新
许多新
多新
新====》得到一个词–新
天来了许多
来了许多
了许多
许多====》得到一个词–许多
今天来了
天来了
来了
了====》得到一个词–了
今天来
天来
来====》得到一个词–来
今天====》得到一个词–今天
最后反向最大匹配的结果是: /今天/来/了/许多/新/同事/
正向最大匹配和反向最大匹配的结果并不一定相同。我一个人吃饭这句话, 按照上述正向最大匹配的结果是:/我/一个/人/吃饭/;按照上述逆向最大匹配的结果是:/我/一/个人/吃饭/。这次两种方式的结果就不一致了。
借助于C++STL的map和BM算法的思想,我简单实现了这两种算法。
#include<map>
#include<string>
#include<iomanip>
#include<iostream>
using namespace std;
int main()
{
string str;
map<int,string> dict;
int maxlength=0,temp=0,i,j,size;
cin>>size;
for(i=0;i<size;i++)
{
temp=0;
cin>>str;
if(str.length()>maxlength) maxlength=str.length();
//记录词典中字符串的最大长度
for(j=0;j<str.length();j++)
{
temp+=str[j];
temp=temp*10;
}
dict[temp]=str;
//制作key-value键值对
}
i=0,j=0;
cin>>str;
int pos=-1;
map<int,string>::iterator map_it;
//从前向后匹配
while(i<str.length())
{
temp=0;
for(j=i;j<str.length();j++)
{
temp+=str[j];
temp=temp*10;
map_it=dict.find(temp);
if(map_it!=dict.end()) pos=j;
//如果匹配成功记录匹配的位置
if(map_it!=dict.end()&&j==str.length()-1)
{
cout<<str.substr(i,j)<<endl;
i=str.length();
break;
}
//如果已经到末尾了就不需要记录位置直接输出即可
if(map_it==dict.end()&&(j-i>=maxlength-1||j==str.length()-1))
{
if(pos==-1)
//如果没有匹配成功进行单字切分向后移动一个字继续匹配
{
cout<<str.substr(i,2)<<endl;
i+=2;
break;
}
else
//如果匹配成功输出并移动到匹配成功后的下一个位置继续匹配
{
cout<<str.substr(i,pos-i+1)<<endl;
i=pos+1;
pos=-1;
break;
}
}
}
}
}
#include<map>
#include<string>
#include<iomanip>
#include<iostream>
using namespace std;
int main()
{
string str;
map<int,string> dict;
int maxlength=0,temp=0,i,j,size;
cin>>size;
for(i=0;i<size;i++)
{
temp=0;
cin>>str;
if(str.length()>maxlength) maxlength=str.length();
//记录词典中字符串的最大长度
for(j=str.length()-1;j>=0;j--)
{
temp+=str[j];
temp=temp*10;
}
dict[temp]=str;
//制作key-value键值对
}
cin>>str;
int pos=-1;
i=j=str.length()-1;
map<int,string>::iterator map_it;
//从后向前匹配
while(i>=0)
{
temp=0;
for(j=i;j>=0;j--)
{
temp+=str[j];
temp=temp*10;
map_it=dict.find(temp);
if(map_it!=dict.end()) pos=j;
//如果匹配成功记录匹配的位置
if(map_it!=dict.end()&&j==0)
{
cout<<str.substr(0,i-j+1)<<endl;
i=-1;
break;
}
//如果已经到末尾了就不需要记录位置直接输出即可
if(map_it==dict.end()&&(i-j>=maxlength-1||j==0))
{
if(pos==-1)
//如果没有匹配成功进行单字切分向后移动一个字继续匹配
{
cout<<str.substr(i-1,2)<<endl;
i-=2;
break;
}
else
//如果匹配成功输出并移动到匹配成功后的下一个位置继续匹配
{
cout<<str.substr(pos,i-pos+1)<<endl;
i=pos-1;
pos=-1;
break;
}
}
}
}
}
标签:
原文地址:http://blog.csdn.net/qq_32400847/article/details/51361664