constchar*szInputFileName="c:
\\Text.txt";
ifstreamifs(szInputFileName);
stringszTemp;
stringstr1,str2,str3,str;
chara[10];//
mapwmap;
//统计双字的
while(ifs)
{
while(ifs.peek()=='\n')ifs.get();
while(ifs.peek()=='')ifs.get();
while(!
ifs.peek()&0x80)ifs.get();
ifs.get(a,3,'');
if(a[0]&0x80)
{
str1=a;
while(ifs.peek()=='\n')continue;
while(ifs.peek()=='')continue;
while(!
ifs.peek()&0x80)ifs.get();
ifs.get(a,3,'');
if(a[0]&0x80)str2=a;
if(str1!
=","&&str1!
="。
"&&str1!
="?
"&&str1!
="!
"&&str1!
=""&&str2!
=","&&str2!
="。
"&&str2!
="?
"&&str2!
="!
"&&str2!
="")
{
szTemp=str1+str2;
wmap[szTemp]++;
}
if(ifs.peek()!
='\n'&&ifs.peek()!
='')ifs.seekg(-2,ios:
:
cur);
}
}
ifs.close();
//三字
ifstreamifs1(szInputFileName);
while(ifs1)
{
while(ifs1.peek()=='\n')ifs1.get();
while(ifs1.peek()=='')ifs1.get();
while(!
ifs1.peek()&0x80)ifs1.get();
ifs1.get(a,3,'');
if(a[0]&0x80)
{
str1=a;
while(ifs1.peek()=='\n')continue;
while(ifs1.peek()=='')continue;
while(!
ifs1.peek()&0x80)ifs1.get();
ifs1.get(a,3,'');
if(a[0]&0x80)str2=a;
elsecontinue;
while(ifs1.peek()=='\n')continue;
while(ifs1.peek()=='')continue;
while(!
ifs1.peek()&0x80)ifs1.get();
ifs1.get(a,3,'');
if(a[0]&0x80)str3=a;
elsecontinue;
if(str1!
=","&&str1!
="。
"&&str1!
="?
"&&str1!
="!
"&&str1!
=""&&str2!
=","&&str2!
="。
"&&str2!
="?
"&&str2!
="!
"&&str2!
=""&&str3!
=","&&str3!
="。
"&&str3!
="?
"&&str3!
="!
"&&str3!
="")
{
szTemp=str1+str2+str3;
wmap[szTemp]++;
}
if(ifs1.peek()!
='\n'&&ifs1.peek()!
='')ifs1.seekg(-4,ios:
:
cur);
}
}
ifs1.close();
//单字
ifstreamifs2(szInputFileName);
while(ifs2)
{
while(ifs2.peek()=='\n')ifs2.get();
while(ifs2.peek()=='')ifs2.get();
while(!
ifs2.peek()&0x80)ifs2.get();
ifs2.get(a,3,'');
if(a[0]&0x80)
{
str=a;
}
if(str!
=","&&str!
="。
"&&str!
="?
"&&str!
="!
"&&str!
="")
{
szTemp=str;
wmap[szTemp]++;
}
}
ifs2.close();
display_map(wmap);
returnfalse;
}
voiddisplay_map(map&wmap)
{
intsum=0;
map:
:
const_iteratormap_it;
for(map_it=wmap.begin();map_it!
=wmap.end();map_it++)//统计总数
{
sum+=map_it->second;
}
for(map_it=wmap.begin();map_it!
=wmap.end();map_it++)//计算词频
{
cout<<"(\""<first<<"\","<second<<")";
cout<<(double)map_it->second/(sum-1)<}
for(map_it=wmap.begin();map_it!
=wmap.end();map_it++)//计算词频
{
ofs<<"(\""<first<<"\","<second<<")";
ofs<<(double)map_it->second/sum<}
}
②宋词生成
#include
#include
#include
#include
usingnamespacestd;
voiddisplay_map(map&wmap);
voidci(inta);
mapwmap;
mapwmapp;
intmain()
{
cout<<"开始:
"<constchar*szInputFileName="c:
\\Text.txt";
ifstreamifs(szInputFileName);
stringszTemp,szTempp;
stringstr1,str2,str;
chara[10];//
//统计双字的
while(ifs)
{
while(ifs.peek()=='\n')ifs.get();
while(ifs.peek()=='')ifs.get();
ifs.get(a,3,'');
if(a[0]&0x80)
{
str1=a;
while(ifs.peek()=='\n')continue;
while(ifs.peek()=='')continue;
ifs.get(a,3,'');
if(a[0]&0x80)str2=a;
if(str1!
=","&&str1!
="。
"&&str1!
="?
"&&str1!
="!
"&&str1!
=""&&str2!
=","&&str2!
="。
"&&str2!
="?
"&&str2!
="!
"&&str2!
="")
{
szTemp=str1+str2;
wmap[szTemp]++;
}
if(ifs.peek()!
='\n'&&ifs.peek()!
='')ifs.seekg(-2,ios:
:
cur);
}
}
ifs.close();
//display_map(wmap);
//单字
ifstreamifs1(szInputFileName);
while(ifs1)
{
while(ifs1.peek()=='\n')ifs1.get();
while(ifs1.peek()=='')ifs1.get();
ifs1.get(a,3,'');
if(a[0]&0x80)
{
str=a;
}
if(str!
=","&&str!
="。
"&&str!
="?
"&&str!
="!
"&&str!
="")
{
szTemp=str;
wmapp[szTemp]++;
}
}
ifs1.close();
//display_map(wmapp);
intas;
while
(1)
{
cout<<"请随意输入一个数来创造宋词:
(输入0时退出)"<cin>>as;
if(as==0)return0;
ci(as);
cout<cout<<"-----------------------------------------------------------------------------"<cout<}
returnfalse;
}
voidci(inta)
{
cout<<"如梦令"<map:
:
iteratormap_it;
for(inti=0;i<3;i++)
{
map_it=wmap.begin();
for(intj=0;j<(rand()+a*2)%(wmap.size());j++)map_it++;
cout<first;
}
cout<<"。
";
for(i=0;i<3;i++)
{
map_it=wmap.begin();
for(intj=0;jcout<first;
}
cout<<"。
";
for(i=0;i<2;i++)
{
map_it=wmap.begin();
for(intj=0;jcout<first;
}
map_it=wmapp.begin();
for(intj=0;j<(rand()+a*3)%(wmapp.size());j++)map_it++;
cout<first;
cout<<",";
for(i=0;i<3;i++)
{
map_it=wmap.begin();
for(intj=0;j<(rand()+a)%(wmap.size());j++)map_it++;
cout<first;
}
cout<<"。
";
map_it=wmap.begin();
for(j=0;j<(2*rand()+a)%(wmap.size());j++)map_it++;
stringtemp=map_it->first;
cout<"<";
for(i=0;i<3;i++)
{
map_it=wmap.begin();
for(intj=0;j<(a*rand())%(wmap.size());j++)map_it++;
cout<first;
}
cout<<"。
"<}
voiddisplay_map(map&wmap)
{
map:
:
const_iteratormap_it;
for(map_it=wmap.begin();map_it!
=wmap.end();map_it++)
{
cout<<"(\""<first<<"\","<second<<")"<}
}
四.系统演示与分析
(1)截图
①字统计:
②宋词生成(如梦令):
(2)结果分析
五.对次实验的感想、意见和建议
通过此次实验,能熟练利用MAP容器,为接下来的两个实验打好基础。
也能对汉字进行操作,清楚的了解到汉字在计算机中的存储方式有别于字符型。
利用位运算&来与0x80进行比对以区分全角字符和半角字符。
但因为将字作为了map的key值,所以输出的列并不是按照出现频率由大到小,这是可以进行改进的方面。
在宋词生成的程序中,主要是利用随机输入的数字来产生伪随机数,以便利用产生的伪随机数选择不同出现频率的词组来生成宋词。
我觉得可以改进的方面是,在统计时就能用程序自动获取不同词牌名的不同格式,在生成宋词时能选择不同的词牌名以生成不同宋词,使程序更加智能。
实验二人民日报词频统计
一.研究背景
词是自然语言中能够独立运用的最小单位,是自然语言处理的基本单位。
自动词法分析就是利用计算机对自然语言的形态(morphology)进行分析,判断词的结构和类别等。
而词频统计是分词系统的基础和关键,只有在正确、准确、快速的词频统计的情况下才能很好的进行分词算法。
二.实验所采用的开发平台及语言工具
实验在WIN7的环境下利用VC++编程。
三.系统设计
(1)算法基本思想
从文本中字符,判断是否为中文字符(全角字符),若为全角字符则根据需要继续读取,即读取两个或三个字。
利用map容器来存储统计结果。
(2)流程图
(3)代码
#include
#include
#include
#include
#include
#include
usingnamespacestd;
//人民日报的词频统计
typedefpairPAIR;
vectorvecpair;
voiddisplay_map(map&wmap);
ofstreamofs("c:
\\fenciout.txt");
intcmp(constPAIR&x,constPAIR&y)//vector的sort()降序排列
{
returnx.second>y.second;
}
intmain()
{
cout<<"开始:
"<constchar*szInputFileName="c:
\\cidian.txt";
ifstreamifs(szInputFileName);
stringszTemp;
stringstr1,str2,str3,str;
chara[100];//
mapwmap;
mapwmapok;
//统计
while(ifs)
{
szTemp="";
inti=0;
ifs>>a[i];//逐个字符读入
if(ifs.eof())
break;
if(!
(a[i]&0x80))//非中文
continue;
if(!
(a[i]&0xB0))//除去空格
{
ifs>>a[i];
continue;
}
while(a[i]!
='/')//读取
{
szTemp+=a[i];
i++;
ifs>>a[i];
}
wmap[szTemp]++;//对应字频加1
}
ifs.close();
//map根据value排序
map:
:
const_iteratorcurr;
for(curr=wmap.begin();curr!
=wmap.end();++curr)
{
vecpair.push_back(make_pair(curr->first,curr->second));
}
sort(vecpair.begin(),vecpair.end(),cmp);//调用排序函数,则vecpair中的first是词,而且降序排列
for(inti=0;i{
ofs<<"<"<"<}
display_map(wmap);
return;
}
voiddisplay_map(map&wmap)
{
intsum=0;
map:
:
const_iteratormap_it;
for(map_it=wmap.begin();map_it!
=wmap.end();map_it++)//统计总数
{
sum+=map_it->second;
}
for(map_it=wmap.begin();map_it!
=wmap.end();map_it++)//计算词频,在界面上输出,此时是无序的
{
cout<<"(\""<first<<"\","<second<<")";
cout<<(double)map_it->second/sum<}
}
四.系统演示与分析
(1)截图
排序后:
(2)结果分析
五.对次实验的感想、意见和建议
在这次实验后,能含有分词字符的文件进行读取,利用语料来训练程序,并将结果保存在文件当中,以便实验三可以使用。
而且能够进行排序,按照value的值,即词语出现次数由高到低进行排序。
美中不足的是,程序运行速度有待提高。
由于map是按照键值排序的,所以引入了vector,并利用vector的sort函数进行排序,熟悉了这两种容器的使用,提高了对c++库函数的认识。
实验三人民日报分词
一.研究背景
自动词法分析就是利用计算机对自然语言的形态(morphology)进行分析,判断词的结构和类别等。
自动分词是汉语句子分析的基础,而且,词语的分析具有广泛的应用(词频统计,词典编纂,文章风格研究等)
二.模型方法
正向最大匹配算法(ForwardMM,FMM)。
这种算法使得程序简单易行,开发周期短,而且仅需要很少的语言资源(词表),不需要任何词法、句法、语义资源。
三.系统设计
(1)算法基本思想
FMM算法描述:
(1)令i=0,当前指针pi指向输入字串的初始位置,执行下面的操作:
(2)计算当前指针pi到字串末端的字数(即未被切分字串的长度)n,如果n=1,转(4),结束算法。
否则,令m=词典中最长单词的字数,如果n(3)从当前pi起取m个汉字作为词wi,判断:
(a)如果wi确实是词典中的词,则在wi后添加一个切分标志,转(c);
(b)如果wi不是词典中的词且wi的长度大于1,将wi从右端去掉一个字,转(a)步;否则(wi的长度等于1),则在wi后添加一个切分标志(单字),执行(c)步;
(c)根据wi的长度修改指针pi的位置,如果pi指向字串末端,转(4),否则,i=i+1,返回
(2);
(4)输出切分结果,结束分词程序。
(2)流程图
图1.分词流程图
图2.FMM算法流程图
(3)代码
#include
#include
#include
#include
#include
#include
usingnamespacestd;
//人民日报的词频统计
typedefpairPAIR;
vectorvecpair;
ofstreamofs("c:
\\fenciout.txt");
intcmp(constPAIR&x,constPAIR&y)
{
returnx.second>y.second;
}
intmain()
{
cout<<"开始:
"<constchar*szInputFileName="c:
\\cidian.txt";
ifstreamifs(szInputFileName);
st