文本文件单词统计(C语言)

文本文件单词统计(C语言)

本人目前还是一位在校大学生,写文章的目的是为了记录一下当前所学,与其他爱好者或从业者相互学习交流。文本文件单词统计这个题目是学校的一次课程设计中的一道,在编写时也是参考了很多资料,借鉴了一些别人的想法,如有冒犯我会及时删除。同样,我的编写成果肯定会存在一些不足之处,也请读者多多包涵。
这个题目的具体信息如下:
1、问题描述
编写一个文本文件单词统计的程序,包括建立文件、单词统计、单词查询、单词定位的功能。

2、基本要求
程序应先询问用户的 ID号(ID 号包括两个大写字母和4 位数字),例如:请输入用户 ID 号:AB1234 ,程序应对输入的 ID 号验证,符合 ID 号要求的格式(检验ID并不是主要要求,大家可自行忽略),然后程序提示四种选择:
(1) 建立文件
(2) 单词统计
(3) 单词查询及定位
(4) 退出
注意:
i) 文件至少包含50个英文单词(一定出现重复的单词,且一定包含数字)
ii) 文档不规范,单词之间可能不只有一个空格,并且有加引号的一些单词“jiaozi” 加引号的单词算单词,但数字不算单词
iii) 逐行扫描文本文件,计算文档中单词总数,及各个单词出现的频次,并且按照单词首字母abcd…… 的顺序排列,显示并生成soft.txt文件
iv) 查询任意给出的单词是否存在,如果不存在,在屏幕上输出“查无此词!”;如果存在,显示单词出现的总次数,并且详细列出其出现的位置。
例如:
请您输入待查询的词:of
单词 of 共出现了2次;
第1次出现在第1行,第5个位置;
第2次出现在第3行,第1个位置。
请您输入待查询的词:

3、问题分析
解决如下问题:
1.检测用户ID格式是否正确,要求(1)用户ID位数为6;(2)前两位为大写英文字母,后四位是数字;
2.可创建文本文件并可输入内容;
3.对文本文件中的单词数进行统计,要求:(1)输出时将单词按照字典顺序排序;(2)数字不算入总数;(3)引号内的单词也算入总数;
4.实现单词定位,要求(1)输出单词出现的详细位置;(2)输出该单词出现的次数

1.4、功能实现
i.检验用户ID:用户从键盘中输入一个字符串。程序将接受的字符串赋值到一个字符数组,遍历数组中的元素判断格式是否正确。

ii.建立文本文件:(1)定义一个串变量;(2)定义文本文件;(3)输入文件名,打开该文件;(4)循环读入文本行,写入文本文件,其过程如下:
While(不是文件输入结束){
读入一文本行至串变量;
串变量写入文件;
输入是否结束输入标志;}
(5)关闭文件。

iii.朴素匹配算法:该算法是整个单词检索程序的核心。对于主串的每一个字符作为子串的开头,与要匹配的字符串进行匹配,对主串做最大的循环,每个字符开头都做子串长度的小循环,直到匹配成功或者全部遍历完成为止。更具体地说:设有三个指针i,j,k,用i指示主串S每次开始比较的位置;指针j,k分别指示主串S和模式串T中当前正在等待比较的字符位置;一开始从主串S的第一个字符(i=0;j=1)和模式T的第一个字符(k=0)比较,若相等,则继续逐个比较后续字符(j++,k++)。否则从主串的下一个字符(i++)起再重新和模式串(j=0)的字符开始比较。依此类推,直到模式T中的所有字符都比较完,而且一直相等,则称匹配成功,并返回位置 i;否则返回-1,表示匹配失败。(可能讲述地不清楚,读者可再查询其他资料进行学习)

iv. 单词统计:
单词总个数统计:在下文提到的单词出现频率统计的过程结束之后,将每个单词出现的次数相加就是单词的总个数。

单词之间有多个空格。在进行判断时,若空格之后仍然是空格,则多个空格作为一个空格进行处理。

单词出现频率统计:逐行扫描文本,将不同的单词放在一个字符数组中。在扫描过程中,每遇到一个与已保存在数组中的某一个单词相同的单词的时候,该单词的计数加1。

按字典顺序排序:将数组中的每个元素(即单词)采用冒泡法排序,最后输出详细的单词出现频率。

v.单词查询:遍历保存单词的字符数组,将要查询的单词与数组元素挨个比对。若不存在,则显示“查无此词”。

vi.单词定位:确定要检索的文本文件,确定要检索的单词,逐行扫描文本,将所要查询的单词与文本比对,若相同则立即输出行数和相应位置。

源代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>


typedef struct{
	char str[50]; //单词最大长度设为50
	int cnt;      //单词出现次数
}Str;			  //存放一个单词 

int vcount(char* p){							//统计文本中单词个数 
	FILE *fp;
	char temp[50];    //在进行冒泡排序时临时存放单词 
    char tmp[50];     //用于在从文件中读取单词时临时存放单词 
	Str words[200];   //单词数量上限(200)
	int num=0,count=0;//实际单词数量:num的值为不同的单词个数,count的值为总单词个数 
	int i,j,neww=1;   //neww标志位,判断是否为新单词 
	int m,n;
	if((fp=fopen(p,"r"))==NULL){
        printf("找不到文件\n");
        return -1;
    }
	loop: while(fscanf(fp,"%s",tmp)!=EOF){		//fscanf从文件中挨个读取单个字符串 (单词)								
		neww=1;
		for(i=0;i<50;i++){						//若读入的是数字则读取下一个字符串(因为数字不计入单词数) 
			if(tmp[i]>='0'&&tmp[i]<='9'){
				goto loop;
			}
		}
		for(i=0;i<50;i++){						//读入的字符串(单词)中可能包含标点符号",""."和自定义的结束标记"$" ,遇到这些符号将字符串断开 
			if(tmp[i]=='$'||tmp[i]==','||tmp[i]=='.') 
				tmp[i]='\0';
		}
		for(i=0; i<num; i++){
			//重复的单词 
			if (strcmp(tmp, words[i].str)==0 ){ //和已经读取的单词进行比对,看是否为新单词。若不是,则单词出现次数加1 
				neww=0;
				words[i].cnt++;
			}
		}
		if (neww){								//若是新单词,则复制字符串进入word数组 
			for (j=0; tmp[j]!='\0'; j++) {
				words[num].str[j] = tmp[j];
			}
			words[num].str[j] = '\0';			//单词末尾添加结束符
			words[num++].cnt = 1;				// 新单词数量+1
		}
	}
	for(m=0;m<num-1;m++){								//采用冒泡排序实现单词的字典排序 
		for(n=0;n<num-1;n++){
			if(strcmp(words[n].str,words[n+1].str)<0)   //A>B,返回正数;A<B,返回负数;A=B,返回0
			{
				strcpy(temp,words[n].str); 				//数字可以用“=”交换,字符串用strcpy函数
				strcpy(words[n].str,words[n+1].str);
				strcpy(words[n+1].str,temp);
			}
		}
	}
	for(m=0;m<num;m++){							//统计单词总数 
		count += words[m].cnt;
	} 
	printf("一共%d个不同的单词,每个单词出现次数如下:\n",num);//输出信息
	for (i=num-1; i>=0; i--) {
		printf("%-10s %2d\n", words[i].str, words[i].cnt);
	}
	printf("单词个数为(包含重复出现)%d\n",count); 
    fclose(fp);
}


int Index(char* p){									//朴素模式匹配算法
	int j=0,i=0;//j用于记录输入的子串的长度,i用于记录主串的长度
	char S[1000],T[50];	//s[]存放文件中的字符,t[]存放要搜索的单词 
    char ch1,ch2;									
    FILE *fp;
    if((fp=fopen(p,"r"))==NULL){
        printf("找不到文件\n");
        return -1;
    }
    ch1=fgetc(fp);			//将文件读取到一维数组当中
    while(ch1!='$'){
    	S[i]=ch1;
        i++;
        ch1=fgetc(fp);
    }
    S[i]='$';
    printf("请输入你要搜索的单词:\n");  //建立子串(输入想要搜索的单词) 
    scanf("%s",T);
	ch2=T[0];
    while(ch2!='\0'){					//j代表了所要搜索的单词的长度 
    	j++;
    	ch2=T[j]; 
	}
    //朴素模式匹配算法实现
    int row=1,col=1;//row为行,col为列 
    int m=0,n=0,q=1;//m为S(主串)的下标,n为T(子串)的下标,q用于换行时记录m的值
    int num=0;//num用于记录选定单词出现的次数
    int left=0;//判断左右引号 
    while(m<i){
        if(S[m]=='"'){								//加引号的单词处理:跳过引号,读取下一个字符,并设置标记left=1 
        	m=m+1;
        	left=1;
		}
		if(S[m]==T[n]){
            m++;
            n++;
        }
        else{
            m=m-n+1;
            n=0;
        };

        if(n==j&&S[m+1]!=' '){						//匹配到相应单词 
            num++;									//出现次数加1 
            if(row==1){
                col=m-n+1;
                printf("第%d次出现的位置位于第%d行第%d列\n",num,row,col);
            }
            else{
                col=m-n-q; 
                printf("第%d次出现的位置位于第%d行第%d列\n",num,row,col);
            }
        }

		if(S[m]==' '||(S[m]=='"' &&left==1)){					//遇到右引号的情况下和空格进行一样的处理 
			col++;
			left=0;
			while(S[m]==' '||S[m]=='"') 
				m=m+1;
		}
    	if(S[m]=='\n'){
        	row++;
        	q=m;
    	};

    	if(S[m]=='$'){
        	printf("所选单词出现的次数是%d\n",num);
        	return num;
    	}
	}
}

void createfile(char* p){									//创建文件 
	FILE *fp;
    char ch;
    fp=fopen(p,"w+");
   	ch=getchar();											//写入文件 
    printf("请输入单词:(请以$符号结束)\n");
    while(ch!='$')
    {
        ch=getchar();
        fputc(ch,fp);
     }
    fclose(fp);
}

int checkID(char s[],int x) {                              // 检验ID  ID格式;共6位 前两位大写字母 后四位为数字 
	int i = 0,y = x; 
	char t[6];
	if(strlen(s)!=6){
		printf("您输入的格式不正确(位数不是6位),请重新输入!\n");
		return 1;
	}
	for(i=0;i<y;i++){
		t[i] = s[i];
	}
	for(i=0;i<y;i++){      //判断前两位 
		if(i<2){
			if(t[i]>='A'&&t[i]<='Z')  ;
			else {
			    printf("您输入的格式不正确(前两位不是大写英文字母),请重新输入!\n"); 
			    return 1;
				break;
			}
		}
		if(i>=2){          //判断后四位 
			if(t[i]>='0'&&t[i]<='9')   ;
			else {
			 	printf("您输入的格式不正确(后四位中包含非数字字符),请重新输入!\n",i+1);
				return 1;
			   	break;
			}
		}
	}
}


int main(){
	int j = 1,l = 0;
	int count=-1,c=-1;
	char filename[255],afilename[255];
	char *p;
	char ID[6];
	char quit;
	while(j==1){                   // 调用cheakID函数对用户名进行判断 
		printf("请输入您的ID!(前两位为大写字母,后四位为整数)\n");
		scanf("%s",ID);
		j = checkID(ID,sizeof(ID));
		if(j==0){
			printf("输入正确!"); 
		}
	}
	while(true){ 
		printf("请选择您想要进行的操作(请输入操作前对应的数字)\n  1.建立文件\n  2.单词查询及定位\n  3.单词统计\n  4.退出\n");
		scanf("%d",&l);    
		fflush(stdin);			//吃掉回车符 
		if(l!=1&&l!=2&&l!=3&&l!=4){         
			printf("您的输入有误,请重新输入!");
		}
		if(l==1){
			printf("请输入所要创建的文件名(包括扩展名)");
			scanf("%[^\n]",filename);
			p=filename;
			createfile(p);  
			printf("文件创建成功!");           // 建立文件 
		}
		if(l==2){           					// 具体单词定位及查询 
			while(count==-1){
				printf("请输入文件名(包括扩展名)");
				scanf("%[^\n]",afilename);
				fflush(stdin);
				p=afilename;
				count=Index(p);
				if(count==0){
					printf("查无此词!");
				}
				if(count==-1){
					printf("文件名有误,请重新进入查询!\n");
					break; 
				}	
			}
		}
		if(l==3){
			while(c==-1){
				printf("请输入文件名(包括扩展名)");
				scanf("%[^\n]",afilename);
				fflush(stdin);
				p=afilename;
				c=vcount(p);
				if(c==-1){
					printf("文件名有误,请重新进入查询!\n");
					break;
				}
			}	
		}
		if(l==4){
			printf("您已退出该程序!"); 
			break;                    			//退出练习程序 
		}
	}
}	

部分运行结果截图:
创建文件,输入文本
单词统计(每个单词的出现频率)
单词统计(每个单词的出现频率)
单词定位

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值