《自然语言处理导论》中文分词程序实验报告.docx
《《自然语言处理导论》中文分词程序实验报告.docx》由会员分享,可在线阅读,更多相关《《自然语言处理导论》中文分词程序实验报告.docx(15页珍藏版)》请在冰豆网上搜索。
![《自然语言处理导论》中文分词程序实验报告.docx](https://file1.bdocx.com/fileroot1/2023-4/20/6925219b-d57d-4392-aff8-3c3157b3b25b/6925219b-d57d-4392-aff8-3c3157b3b25b1.gif)
《自然语言处理导论》中文分词程序实验报告
《自然语言处理导论》
中文分词实验报告
一、实验目的
了解中文分词意义
掌握中文分词的基本方法
二、实验环境
Win764位
DEV-C++编译器
三、实验设计
(一)分词策略
目前较为成熟的中文分词方法主要有:
1、词典正向最大匹配法
2、词典逆向最大匹配法
3、基于确定文法的分词法
4、基于统计的分词方法
一般认为,词典的逆向匹配法要优于正向匹配法。
基于确定文法和基于统计的方
法作为自然语言处理的两个流派,各有千秋。
我设计的是根据词典逆向最大匹配法,基本思路是:
1、将词典的每个词条读入内存,最长是4字词,最短是1字词;
2、从语料中读入一段(一行)文字,保存为字符串;
3、如果字符串长度大于4个中文字符,则取字符串最右边的4个中文字符,作
为候选词;否则取出整个字符串作为候选词;
4、在词典中查找这个候选词,如果查找失败,则去掉这个候选词的最左字,重
复这步进行查找,直到候选词为1个中文字符;
5、将候选词从字符串中取出、删除,回到第3步直到字符串为空;
6、回到第2步直到语料已读完。
(二)程序设计
查找算法:
哈希表
汉字编码格式:
UTF-8
程序流程图:
YES
源代码:
#include
#include
#include
#include
#include
#include
#include
#include
#defineMaxWordLength12//最大词长字节(即4个汉字)
#defineSeparator""//词界标记
#defineUTF8_CN_LEN3//汉字的UTF-8编码为3字节
usingnamespacestd;
usingnamespace__gnu_cxx;
namespace__gnu_cxx
{
template<>structhash:
string>
{
size_toperator()(conststd:
:
string&x)const
{
returnhash()(x.c_str());
}
};
}
hash_mapwordhash;//词典
//读入词典
voidget_dict(void)
{
stringstrtmp;//读取词典的每一行
stringword;//保存每个词
typedefpairsipair;
ifstreaminfile("CoreDict.txt.utf8");
if(!
infile.is_open())
{
cerr<<"Unabletoopeninputfile:
"<<"wordlexicon"
<<"--bailingout!
"<system("pause");
exit(-1);
}
while(getline(infile,strtmp))//读入词典的每一行并将其添加入哈希中
{
istringstreamistr(strtmp);
istr>>word;//读入每行第一个词
wordhash.insert(sipair(word,1));//插入到哈希中
}
infile.close();
}
//删除语料库中已有的分词空格,由本程序重新分词
stringdel_space(strings1)
{
intp1=0,p2=0;
intcount;
strings2;
while(p2//删除半角空格
if(s1[p2]==32)
{
if(p2>p1)
s2+=s1.substr(p1,p2-p1);
p2++;
p1=p2;
}
else
{
p2++;
}
}
s2+=s1.substr(p1,p2-p1);
returns2;
}
//用词典做逆向最大匹配法分词
stringdict_segment(strings1)
{
strings2="";//用s2存放分词结果
while(!
s1.empty()){
intlen=(int)s1.length();//取输入串长度
if(len>MaxWordLength)//如果输入串长度大于最大词长
{
len=MaxWordLength;//只在最大词长范围内进行处理
}
stringw=s1.substr(s1.length()-len,len);
intn=(wordhash.find(w)!
=wordhash.end());//在词典中查找相应的词
while(len>UTF8_CN_LEN&&n==0)//如果不是词
{
len-=UTF8_CN_LEN;//从候选词左边减掉一个汉字,将剩下的部分作为候选词
w=s1.substr(s1.length()-len,len);
n=(wordhash.find(w)!
=wordhash.end());
}
w=w+Separator;
s2=w+s2;
s1=s1.substr(0,s1.length()-len);
}
returns2;
}
//中文分词,先分出数字
stringcn_segment(strings1)
{
//先分出数字和字母
strings2;
intp1,p2;
p1=p2=0;
while(p2while(p2<=(s1.length()-UTF8_CN_LEN)&&(s1.substr(p2,UTF8_CN_LEN).at(0)<'0'||s1.substr(p2,UTF8_CN_LEN).at(0)>'9')){//不是数字或字母
p2+=UTF8_CN_LEN;
}
s2+=dict_segment(s1.substr(p1,p2-p1));//之前的句子用词典分词
//将数字和字母分出来
p1=p2;
p2+=3;
while(p2<=(s1.length()-UTF8_CN_LEN)&&(s1.substr(p2,UTF8_CN_LEN).at(0)>='0'&&s1.substr(p2,UTF8_CN_LEN).at(0)<='9')){//是数字或字母
p2+=UTF8_CN_LEN;
}
p1=p2;
}//endwhile
returns2;
}
//在执行中文分词前,过滤半角空格以及其他非UTF-8字符
stringseg_analysis(strings1)
{
strings2;
strings3="";
intp1=0;
intp2=0;
intcount;
while(p2if(((s1[p2]>>4)&14)^14){//过滤非utf-8字符
count=0;
do{
p2++;
count++;
}while((((s1[p2]>>4)&14)^14)&&p2s2=s1.substr(p1,p2-count-p1);//数字前的串
s3+=cn_segment(s2)+s1.substr(p2-count,count)+Separator;//数字
if(p2<=s1.length()){//这个等号,当数字是最后一个字符时!
s1=s1.substr(p2,s1.length()-p2);//剩余串
}
p1=p2=0;
}
else
p2+=UTF8_CN_LEN;
}
if(p2!
=0){
s3+=cn_segment(s1);
}
returns3;
};
intmain(intargc,char*argv[])
{
ifstreaminfile("1998-01-qiefen-file.txt.utf8");//打开输入文件
if(!
infile.is_open())//打开输入文件失败则退出程序
{
cerr<<"Unabletoopeninputfile:
"<"
<system("pause");
exit(-1);
}
ofstreamoutfile1("result.txt.utf8");//确定输出文件
if(!
outfile1.is_open()){
cerr<<"Unabletoopenfile:
SegmentResult.txt"<<"--bailingout!
"
<system("pause");
exit(-1);
}
clock_tstart,finish;
doubleduration;
start=clock();
get_dict();
finish=clock();
duration=(double)(finish-start)/CLOCKS_PER_SEC;
cout<<"词典读入完毕,耗时"<stringstrtmp;//用于保存从语料库中读入的每一行
stringline;//用于输出每一行的结果
start=clock();
cout<<"正在分词并输出到文件,请稍候..."<while(getline(infile,strtmp))//读入语料库中的每一行并用最大匹配法处理
{
line=del_space(strtmp);
line=seg_analysis(line);//调用分词函数进行分词处理
outfile1<}
finish=clock();
duration=(double)(finish-start)/CLOCKS_PER_SEC;
cout<<"分词完毕,耗时"<cout<<"分词结果保存在result.txt.utf8中。
"<system("pause");
return0;
}
结果和性能分析
运行时间:
可以看出,读入词典用时:
0.421s;分词用时:
6.002s。
可能影响速度的包括查表方式的不同,以及存储字的格式不同等等原因。
分词结果:
在结果中,基本上大部分的分词都算是成功的,但是仍有部分短语分析错误。
例如:
“女士们”的分词被分为“女士们”,但是本意应该为连在一起的,但是词典中并无此例,因此分析错误。
四、总结
总的来说,实验比较顺利。
但是仍有无法解决的问题,例如因词典不完善导致的部分词语分词错误或者因为格式不同导致的无法判断等问题有待解决。
分词是中文自然语言处理的基础,在现实中已经得到广泛应用。
因此这个实验让我亲身体验了分词的实现过程,熟悉了分词程序的基本结果,很有收获。