英文词频分析器
有时经常有统计一篇文章中有多少个单词,这时候就需要词频分析器来解决了。
基本思想:
将文件中或用户输入的字符串先存起来,然后从第一个字符开始依次向后扫描,遇到字母,则将其先添加到一个字符串中,然后在向后扫描,若还是字母,则将此字符串连接到刚才的字符串中,若不是字母,则刚才的字符串就是一个单词,这样依次扫描完所有字符。当然,在扫描时,还要与已经存储的单词依次比较,若相同则不再添加,刚才那个单词的词数加一即可。
先截个图SeeSee:
我还将查询的结果保存至Access的数据库中,这里就用到ADO访问数据库的问题,上次我已经将ADO连接类(ADOConn)分装好了,这次只拿来用就行了。
代码:
void ADOConn::OnInitADOConn()
{
// CString sysPath = "C:\\fg\\MuscicPlayer\\";
HRESULT hr;
::CoInitialize(NULL); //初始化OLE/COM环境
hr=m_pConnection.CreateInstance("ADODB.Connection"); //创建connection对象
// 在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
// 因为它有时会经常出现一些意想不到的错误。
try
{
if(SUCCEEDED(hr))
{
char *dbPath="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=WordData.mdb";
hr=m_pConnection->Open(_bstr_t(dbPath),"","",adModeUnknown);
}
// _bstr_t strConnect="Provider=SQLOLEDB;Server=LENOVO-PC;DataBase=Study;uid=sa;pwd=zyc123";
// m_pConnection->Open(strConnect,"","",adModeUnknown);
}
//捕获异常
catch(_com_error e)
{
e.Description();
}
}
void ADOConn::ExitConnect()
{
//关闭记录集和连接
if(m_pRecordset!=NULL)
m_pRecordset->Close();
m_pConnection->Close();
//释放环境
::CoUninitialize();
}
_RecordsetPtr& ADOConn::GetRecordSet(_bstr_t bstrSQL)
{
try
{
//连接数据库,如果conection对象为空,则重新连接数据库
if(m_pConnection==NULL)
OnInitADOConn();
//创建记录集对象
m_pRecordset.CreateInstance(__uuidof(Recordset));
//取得表中的记录
m_pRecordset->Open(bstrSQL,m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
}
catch(_com_error e)
{
e.Description();
}
//返回记录集
return m_pRecordset;
}
BOOL ADOConn::ExecuteSQL(_bstr_t _bstrSQL)
{
_variant_t RecordsAffected;
try
{
//是否已连接数据库
if(m_pConnection==NULL)
OnInitADOConn();
m_pConnection->Execute(_bstrSQL,NULL,adCmdText);
return true;
}
catch(_com_error e)
{
e.Description();
return false;
}
}
当然用数据结构来存最好了。
///////////////存放分出的所有单词的结构体/////////
typedef struct WordStore
{
char word[30];
}wordstore;
/////////存储排好序的单词及个数的结构体///////////
typedef struct WordStoreAll
{
float frequency;
int number;
char word[30];
}wordstoreall;
主类:
//////////////////////////////////////////
class ReadWord
{
int AllWord;
int Count;
bool AddTrue;
wordstore WordNode[MAX];
wordstoreall Word[MAX];
/////数据库操作使用
ADOConn m_AdoConn;
_RecordsetPtr m_pRecordset;
_ConnectionPtr m_pConnection;
char *tablename;
public:
int Choice;
public:
ReadWord();
int GetCount(){ return Count;}
bool GetAddTrue(){return AddTrue;}
char *ReadFromText();
char *ReadFromScreen();
void strcopy(char *dest,const char *sour);
void Transform(char *str);
void GetEveryWord();
void Countword();
void Frequency();
void Order();
void Print(int X);
void color(int a);
///-------数据库操作----------------
void IsAddToAccess(); //判断用户是否将分析结果添加到数据库
void AddToAccess(); //将分析结果添加到数据库
void Select(); //查询数据库中的数据
void CreateTable();
void GetTableName(int n);
void ReadTableName();
void WriteTNameToFile();
};
///////////////////////////////
#include "Readword.h"
///////////////////////////////
///////构造函数//////////////
ReadWord::ReadWord()
{
AddTrue = false;
}
//////////////////加点颜色SeeSee/////////////////////////////
void ReadWord::color(int a) //颜色函数
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a);
}
/////////////从屏幕上读取信息到字符串中/////////////
char *ReadWord::ReadFromScreen()
{
char *string;
string = (char*)malloc(1000);
printf("请输入:");
// fflush(stdout);
gets(string);
return string;
}
/////////////////////////////////////////
/////////////从文件中读取信息到字符串中/////////////
char *ReadWord::ReadFromText()
{
FILE *fp;
char *string;
char FileName[30];
string = (char*)malloc(5000);
if(NULL == string)
{
printf("内存分配失败!\n");
return NULL;
}
printf("请输入文件名(不用输后缀名):");
scanf("%s",FileName);
// gets(FileName);
strcat(FileName,".txt");
fp = fopen(FileName,"rb");
if( NULL == fp)
{
printf("文件打开错误\n");
return NULL;
}
fgets(string,5000,fp);
fclose(fp);
return string;
}
////////////////将非单词的字符转化为空格////////////
void ReadWord::Transform(char *str)
{
while(*str != '\0')
{
if(*str<'a'||*str>'z')
*str=' ';
str++;
}
}
//////////////拷贝函数/////////////////
void ReadWord::strcopy(char *dest,const char *sour)
{
while(*sour != '\0')
{
*dest++=*sour++;
}
*dest='\0';
}
//////////////将每个单词分离出来//////////////////
void ReadWord::GetEveryWord()
{
char tempw[30];
char tempc[2];
char *String;
bool m_flag=false;
int i=0,n=0;
if(1 == Choice)
String = ReadFromText();
else
String = ReadFromScreen();
strlwr(String); ///将大写字母转化为小写字母
Transform(String);
while(1)
{
if(*String != '\0')
{
tempc[0]=*String;
if(' ' != *String)
{
tempw[i++]=tempc[0];m_flag = true;
}
else
{
if(m_flag)
{
m_flag = false;
tempw[i]='\0';
strcopy(WordNode[n].word,tempw);
n++;
for(;i>=0;i--)
tempw[i]=0;
i=0;
}
}
}
else if(*(--String) != ' ') //这时为了将文件最后一个单词因为没加标点,而未能统计的最后一个单词统计进去
{
tempw[i]='\0';
strcopy(WordNode[n].word,tempw);
n++;
for(;i>=0;i--)
tempw[i]=0;
i=0;
break;
}
else
break;
String++;
}
AllWord=n; //得到分离出的总词数
}
//////////////////////对提取出的所有单词计数////////
void ReadWord::Countword()
{
int i,j;
int count=0,m_flag=0;
for(i=0;i<AllWord;i++)
Word[i].number=1;
for(i=0;i<AllWord;i++)
{
m_flag=0;
for(j=0;j<AllWord;j++)
{
if(!strcmp(Word[j].word,WordNode[i].word)) //若有相同的单词,其相应的number加一
{ Word[j].number++;m_flag=1;}
}
if(0 == m_flag) //若原有的单词中没有相同的,则添加此单词到Word中
{
strcopy(Word[count].word,WordNode[i].word);
count++;
}
}
Count=count;
}
////////////////计算每个单词的频率//////////////
void ReadWord::Frequency()
{
int i;
for(i=0;i<Count;i++)
{
Word[i].frequency=(float)Word[i].number/Count;
}
}
////////////////冒泡排序/////////////////////////
void ReadWord::Order()
{
char tempstr[30];
int tempnum;
float tempfre;
int m,n;
for(m=1;m<Count;m++)
for(n=0;n<Count-m;n++)
{
if(strcmp(Word[n].word,Word[n+1].word)>0)
{
//////交换单词
strcopy(tempstr,Word[n].word);
strcopy(Word[n].word,Word[n+1].word);
strcopy(Word[n+1].word,tempstr);
////////交换词数
tempnum = Word[n].number;
Word[n].number = Word[n+1].number;
Word[n+1].number = tempnum;
/////////交换频率
tempfre = Word[n].frequency;
Word[n].frequency = Word[n+1].frequency;
Word[n+1].frequency = tempfre;
}
}
}
///////////////////输出结果//////////////////////
void ReadWord::Print(int X)
{
int i;
printf("对该文本的词频分析如下:\n");
printf("序号\t单词\t 个数\t频率\n");
for(i=0;i<X;i++)
{
printf("%-3d\t%-10s\t%d\t%.2f%%\n",i+1,Word[i].word,Word[i].number,Word[i].frequency*100);
}
}
///////////////从数据库中选择查询结果//////////////
void ReadWord::Select()
{
m_AdoConn.OnInitADOConn(); //初始化链接库类
// char *sql="Select * From Wordtable";
char *q=" ";
char Sql[50];
char *Sql1 ="SELECT * FROM ";
strcopy(Sql,Sql1);
strcat(Sql,tablename);
strcat(Sql,q);
m_pRecordset=m_AdoConn.GetRecordSet((_bstr_t)Sql); //打开并获得记录集
m_pConnection.CreateInstance(__uuidof(Connection)); //创建connection对象
_variant_t var;
char strword[30];
int number;
double frequen;
int i=0;
try
{
if(!m_pRecordset->adoBOF) //表中数据不为空,将记录及指针移到第一条
m_pRecordset->MoveFirst();
else
{
printf("\n数据表为空!\n");
m_AdoConn.ExitConnect();
return ;
}
printf("对该文本的词频分析如下:\n");
printf("序号\t单词\t 个数\t频率\n");
// 读入库中各字段并输出
while(!m_pRecordset->adoEOF)
{
var = m_pRecordset->GetCollect("Word"); //获得一条记录的Word字段信息
if(var.vt != VT_NULL)
strcopy(strword,(LPCSTR)_bstr_t(var));
var = m_pRecordset->GetCollect("Num"); //获得一条记录的Num字段信息
if(var.vt != VT_NULL)
number = var.intVal;
var = m_pRecordset->GetCollect("Frequency");
if(var.vt != VT_NULL)
frequen = var.dblVal;
printf("%-3d\t%-10s\t%d\t%.2lf%%\n",i+1,strword,number,frequen*100);
i+=1;
m_pRecordset->MoveNext();
}
}
catch(_com_error *e)
{
// AfxMessageBox(e->ErrorMessage());
e->Description();
}
m_AdoConn.ExitConnect();
}
//////////////////用户是否同意将结果添加到数据库/////////
void ReadWord::IsAddToAccess()
{
char button;
printf("\n是否将结果添加到数据库?是按[Y],否按其他键。\n");
fflush(stdin);
scanf("%c",&button);
if(button == 'Y' || button == 'y')
{
AddTrue = !AddTrue;
GetTableName(1);
CreateTable();
AddToAccess();
}
}
////////////////将结果添加到数据库中/////////////////////////
void ReadWord::AddToAccess()
{
m_AdoConn.OnInitADOConn();
char *q=" ";
char Sql[50];
char *Sql1 ="SELECT * FROM ";
strcopy(Sql,Sql1);
strcat(Sql,tablename);
strcat(Sql,q);
m_pRecordset=m_AdoConn.GetRecordSet((_bstr_t)Sql); //打开并获得记录集
m_pConnection.CreateInstance(__uuidof(Connection)); //创建connection对象
_variant_t var;
int i;
try
{
if(AddTrue)
{
for(i=0;i<Count;i++)
{
m_pRecordset->AddNew();
m_pRecordset->PutCollect("Word",_variant_t(Word[i].word));
m_pRecordset->PutCollect("Num",_variant_t((long)Word[i].number));
m_pRecordset->PutCollect("Frequency",_variant_t((float)Word[i].frequency));
m_pRecordset->Update();
}
}
printf("\n添加成功!\n\n");
m_AdoConn.ExitConnect();
}
catch(...)
{
printf("操作失败\n");
}
}
//////////////将用户输入的表名存储到文件中////////////////
void ReadWord::WriteTNameToFile()
{
char *Table,*str=" ";
Table = (char*)malloc(20);
strcopy(Table,str);
strcat(Table,tablename);
strcat(Table,str);
FILE *fp;
if((fp = fopen("TableNameList.txt","ab+")) == NULL)
{
printf("不能打开文件\n");
return;
}
if(fwrite(Table,strlen(Table)*sizeof(char),1,fp) != 1)
printf("文件写出错!\n");
fclose(fp);
}
////////////////////存文件中读取表名////////////////////////
void ReadWord::ReadTableName()
{
FILE *fp;
char *string;
char *FileName="TableNameList.txt";
string = (char*)malloc(300);
if(NULL == string)
{
printf("内存分配失败!\n");
return;
}
fp = fopen(FileName,"rb");
if( NULL == fp)
{
printf("文件打开错误\n");
return;
}
fgets(string,300,fp);
fclose(fp);
printf("可供查询的表名如下:\n");
printf("%s\n",string);
}
//////////////获得要创建表的名称或获得要查询表的名称////////////
void ReadWord::GetTableName(int n)
{
tablename = (char*)malloc(20);
fflush(stdin);
if(1 == n)
{
printf("请输入要创建的表名:");
gets(tablename);
WriteTNameToFile();
}
else
{
ReadTableName();
printf("请输入您要查询的表名:");
gets(tablename);
/////////判断
}
}
//////////////////////创建表//////////////////
void ReadWord::CreateTable()
{
m_AdoConn.OnInitADOConn();
// _bstr_t sql;
char Sql[100];
char *Sql1 = "CREATE TABLE ";
char *Sql2 = " (Word varchar(30),Num int,Frequency float)";
strcopy(Sql,Sql1);
strcat(Sql,tablename);
strcat(Sql,Sql2);
if(!m_AdoConn.ExecuteSQL((_bstr_t)Sql))
{
printf("\n创建表失败!\n");
return;
}
m_AdoConn.ExitConnect();
}