题目描述:做一个词频统计程序,该程序具有以下功能:
(1)可倒入任意英文文本文件
(2)统计该英文文件中单词数和各单词出现的频率(次数),并能将单词按字典顺序输出。
(3)可能的话可否将单词及频率写入数据库(文件)
基本要求:
1.系统有界面,有功能选择,帮助等
2.要求程序设计风格良好,有必要的文档注释,函数注释和重要语句注释。
3.需要调试和测试,并在doc文档中完成调试和测试设计和结果记录。
4.其他拓展功能(自由发挥)。
思想:1.使用文件操作。
2.将英文文章先读到一个字符串中。
3.将英文文章中的单词分离时,主要使用strtok函数。
4.将英文单词排序时使用strcmp函数。
遇到的问题:1.当文件为空时,不能正常显示。
2.在进行文章续写时,将所续写的内容读到文件后,会出现一个似空格但又不是
空格的东西,导致单词统计时有错误。
3.续写内容时,应将文件指针一道文件末尾。
主要代码:
/****************************************************************************
Filename:词频统计
Author:
Date:2014.3.31
Description:功能:能够统计单词总个数及各个单词的频数。
能够增加文章内容,文章写入文件中。
能将统计出的单词总数、单词、频数写到
一个文件中。
能按照字典顺序输出单词,并输出出现的频数。
Function: read_e(char *essay,int *total_ch);
show_e(char *essay,int *total_ch);
sort(int *kind)//按照字典排序
add(char *essay,int *total_ch);
dep_show(char *essay,char *b)
menu(int *select)
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_NUM 100000
struct//单词结构体
{
int num;//单词频数
char ch[20];//每一个单词
}word[MAX_NUM];
void read_e(char *essay,int *total_ch,char *ch)//获取文章信息
{
FILE *fp;
int i;
fp=fopen("English essay.txt","r");
if(!fp)
{
printf("\n打开文件English essay.txt失败!");
exit(0);
}
//获取文章及总字符数
(*ch)=fgetc(fp);//ch为文章第一个字符,判断文章文件是否为空。
if(*ch!=EOF)
{
essay[0]=(*ch);
for(i=1;!feof(fp);i++)
essay[i]=fgetc(fp);//获取文章,将文章中的各个字符放到essay数组中
essay[i]=’\0’;//在读取文章时,并没有将字符串的结束标志读进去,为了后面使用strtok等字符串的相关函数,加上’\0’。
(*total_ch)=strlen(essay);
}
fclose(fp);
}
void show_e(char *essay,int *total_ch,char *ch)//显示文章
{
if((*ch)==EOF)
printf("\n文件为空,请选择文章续写!");
else
printf("%s",essay);
printf("\n");
}
void sort(int *kind)//按照字典排序
{
int n,j,t;
char tempt[MAX_NUM];
for(n=0;n<(*kind)-1;n++)
for(j=0;j<(*kind)-n-1;j++)
{
if(strcmp(word[j].ch,word[j+1].ch)==1)
{
strcpy(tempt,word[j].ch);//交换单词
strcpy(word[j].ch,word[j+1].ch);
strcpy(word[j+1].ch,tempt);
t=word[j].num;//交换单词频数
word[j].num=word[j+1].num;
word[j+1].num=t;
}
}
}
void dep_show(char *essay,char *b)
{
int j,i=0;//i记录有多少不同的单词,n记录相同单词出现的次数
char *tok;
bool judge=false;
int sum=0;
FILE *fp;
for(tok=strtok(essay,b);tok!=NULL;tok=strtok(NULL,b))
{
//利用strtok函数将文章中的单词分离开。
sum++;//单词总数
strcpy(word[i].ch,tok);
(word[i].num)=1;
/************************************************
思想:
统计单词频数主要是在
函数void dep_show(char *essay,char *b)里实现。
每分离一个单词将其复制到单词的结构体数组中
并和之前统计的单词比较,若不相同,继续分离单词,
将分离的单词复制到单词的结构体数组下一个元素中;
若相同,则该单词的频数加1,继续分离单词,
将分离的单词复制到单词的结构体数组上一次所得到
的元素中,即覆盖了重复的单词。
*************************************************/
for(j=0;j<i;j++)
if(strcmp(word[i].ch,word[j].ch)==0)
{
(word[j].num)++;
judge=true;
}
if(judge)
i--;
i++;
judge=false;
}
// i=i-1;
sort(&i);
printf("单词总数为:%d\n",sum);
fp=fopen("count.txt","w");
if(!fp)
{
printf("\n打开文件count.txt失败!");
exit(0);
}
fprintf(fp,"单词总数为:%d\n",sum);将单词总数读到文件中
for(j=0;j<i;j++)
{
fprintf(fp,"%-16s\t%d\t\n",word[j].ch,word[j].num);//将单词、单词频数读到文件中
printf("%-16s\t%d\t\n",word[j].ch,word[j].num);//将单词、单词频数打印到屏幕上
}
fclose(fp);
}
void add(char *essay,int *total_ch,char *ch)
{
char essay_write[MAX_NUM];
FILE *fp;
char str=' ';
getchar();
fp=fopen("English essay.txt","a+");
if(!fp)
{
printf("\n打开文件English essay.txt失败!");
exit(0);
}
printf("请输入:");
gets(essay_write);
if((*ch)!=EOF)
fputc(str,fp);
fputs(essay_write,fp);//将新增的文章读到文件上
strcat(essay,essay_write);
read_e(essay,total_ch,ch);
printf("添加成功");
printf("\n");
fclose(fp);
}
void menu(int *select)
{
int item,total_ch=0;//total_ch记录文章中的总字符数
char b[]={',','.','?',':','-',' ',' '},essay[2*MAX_NUM],ch;
printf("\n");
printf("*************************************************\n");
printf(" 词频统计 \n");
printf(" 1.文章续写 \n");
printf(" 2.显示英文文本 \n");
printf(" 3.显示单词总数、全部单词及频数 \n");
printf(" 4.退出 \n");
printf("*************************************************\n");
printf("请选择您需要的操作序号(1-5)按回车确认:");
scanf("%d",&item);
printf("\n");
read_e(essay,&total_ch,&ch);
switch(item)
{
case 1:add(essay,&total_ch,&ch);break;
case 2:show_e(essay,&total_ch,&ch);break;
case 3:dep_show(essay,b);break;
case 4:select=0;break;
default:printf("请在0-6之间选择\n");break;
}
}
void main()
{ int select=1;
while(select)
{
menu(&select);
}
}
小结:1.使用feof()函数时,读到文件末尾,会有一个文件末尾标志的字符,这个字符会被读到essay数组中,这就导致在增加文章时,在原文章末尾和新增文章之间有一个似空格又非空格的东西。如:
文本文件:
本来空格应被strtok函数过滤掉,所以原文章末尾和新增内容之间应该不是空格。
最后就如源代码,改成了使用EOF判断文件是否为空。
在新增文章时,应使用’a’方式打开文件。是指向文件的指针指向文件末尾。
但存在一个问题:
新增内容紧随原文章之后,按照用户意愿应该有间隔。处理方式:
str=' ';
if((*ch)!=EOF)
fputc(str,fp);
当原文件不为空时,将空格放在文件末尾。
结果展示: