SCAU 高程综合实验:文件操作与字符处理

SCAU 高程综合实验:文件操作与字符处理

在当前目录中存在文件名为"case1.in"(其中case后为数字1,不是字母l,写错提交后会判错)的文本文件,
其内容为一篇英文文章(以EOF作为结束标志)。现要求读取该文本文件内容,统计文章中每个单词出现的次数,
并输出出现次数最多的前5个单词及其出现次数(按出现次数由多到少的顺序输出,次数相同时按字典顺序输出,
不足5个单词时,按序输出全部单词)。程序中注意如下细节:
(1) 空格、标点符号与回车符起到分隔单词的作用。
(2) 文章一行的末尾可能有连字符,出现连字符时,该行最末的字符串与下行最先出现的字符串构一个单词;
(3) 名词缩写算一个单词;
(4) 数字不算单词;
(5) 单词不区分大小写;
(6) 输出时单词全使用小写;

#include “stdio.h”
#include “math.h”
#include “string.h”
#include “stdlib.h”


main()
{
_______________________
}

输入格式
文件case1.in中一篇英文文章,包含多段文字,单词数不超过10000,每个单词不超过20个字符

输出格式
按题意输出答案

输入样例
(如case1.in内容如下)
I am a student. My school is SCAU. It is a beau-
tiful university. I like it.

输出样例
a 2
i 2
is 2
it 2
am 1

解题思路分析:
按照解题顺序,分析一下几个重要的点:
第一个考点是文件操作,文件的打开关闭和读写。题目中说扫描单词,又由于有字符串的特殊要求,所以使用fscanf有点小困难,还是使用fgetc逐字扫描、判断。
第二个考点是单词的判断,也是这道题的核心,这个和前面oj上一题对单词的判断读写几乎相同,只是多了个连字符的问题。当扫描到有单词结束的符号(空格、标点等),打上标记,有连字符+换行的话,另作标记。
第三个考点是字符串的存放以及字符串的排序,当然其中也不可避免的有string库中函数的运用。由于扫描完单词后便存入数组,自然要用到字符串数组,其中也变相的考察了学生地址(指针)的概念。排序的话自然是字典序,由于能力有限,使用冒泡+strcpy进行排序。

下面贴一下我的代码(含详注)。

#include "stdio.h"
#include "math.h"
#include "string.h"
#include "stdlib.h"
char sto[10005][25];//字符串数组,无重复 
int num=0;//字符串数组下标 
int count[10005]; //每个单词出现的次数 
int isalpha(char ch) //判断是否为字母(函数库里竟然没有isalpha)
{
	if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')) return 1;
	else return 0;
}
int repeat(char *s)//判断单词是否重复
{
	int i;
	for(i=0;i<num;i++)
	{
		if(!strcmp(sto[i],s))//查重 
		{if(i==0) return 20000;else return i;}//查到重复的单词,则返回单词第一次出现的下标 
	}
	return 0;//没查到,则返回0 
}

main()
{         
	FILE *fp;
	int i,j=0,k;
	char ch;
	int endflag=0,lianflag=0,enter=0;
	for(i=0;i<10005;i++) count[i]=1;//计数器初始化为1
	
	fp=fopen("case1.in","r+");//打开文件 
	if(fp==NULL) {printf("ERROR");return 0;}
	
	while((ch=fgetc(fp))!=EOF)//由于有连字符,用fscanf有点困难,所以开始逐字扫描操作,
	{
		if(isalpha(ch)&&ch>='A'&&ch<='Z') ch+=32; 
		if(isalpha(ch)&&endflag&&!lianflag&&!enter) {enter=0;endflag=0;lianflag=0;j=0;num++;sto[num][j++]=ch;}//新单词的情况,更新连字符、回车、单词结束的标记,建立新一行数组记录下一个单词 
		else if(isalpha(ch)&&endflag==0&&!lianflag&&!enter) {enter=0;lianflag=0;sto[num][j++]=ch;}//同一个单词的情况,即单词续写 
		else if(ch==' '||(lianflag==0&&ch=='\n')||((ch!='-')&&((ch>=32&&ch<=47)||(ch>=49&&ch<=64)||(ch>=91&&ch<=96)||(ch>=123&&ch<=126))))//单词结束,检索到符号、换行,就换单词 
		{
			enter=0;endflag=1;lianflag=0;
			int p=0;
			if(p=repeat(sto[num])) {if(p==20000) p=0;memset(sto[num],0,sizeof(sto[num]));num--;count[p]++;}
		}
		else if(isalpha(ch)&&lianflag&&!enter)//有连字符但无回车的特殊情况,算新单词的出现,也标志着连字符前一个单词的结束,对前一个单词进行查重计数,然后进行新单词建立的操作 
		 {int p=0;
		if(p=repeat(sto[num])) {if(p==20000) p=0;memset(sto[num],0,sizeof(sto[num]));num--;count[p]++;}
		enter=0;endflag=0;lianflag=0;j=0;num++;sto[num][j++]=ch;
		} 

		else if(ch=='-'&&endflag==0)	{enter=0;lianflag=1;}//检索到连字符标记一下 
		else if(ch=='\n') {enter=1;}//检索到换行标记一下 
		else if(lianflag&&isalpha(ch)&&!endflag&&enter) {enter=0;lianflag=0;sto[num][j++]=ch;}//有连字符+回车的情况,是原来的单词,进行单词的续写 
		else {endflag=1;lianflag=0;if(repeat(sto[num])) {memset(sto[num],0,sizeof(sto[num]));num--;count[repeat(sto[num])]++;}} //其余情况(包括数字)算作无单词,进行标记的清除 	
	}
	fclose(fp);//文件扫描结束,关闭文件 
	char t[25];//下面将用到冒泡,建立第三方变量 
	int t2=0;//同理,计数器也要用到冒泡 
	
	for(i=0;i<num-1;i++)//将字符串数组按照字典序排序,使用冒泡排序 
	for(j=0;j<num-1-i;j++)
	if(strcmp(sto[j],sto[j+1])>0) 
	{memset(t,0,sizeof(t));strcpy(t,sto[j]);t2=count[j];strcpy(sto[j],sto[j+1]);count[j]=count[j+1];strcpy(sto[j+1],t);count[j+1]=t2;} 

	int p=0;//扫描次数前五的单词,如果不足五个就直接return 0 
	int max1=0,max2=0,max3=0,max4=0,max5=0; //由于只有五个,就不对次数进行排序了,直接比较依次求最多次数就好,比完把最多的次数清零 
	
	for(i=0;i<=num;i++) if(max1<count[i]) {p=i;max1=count[i];}
	count[p]=0;
	printf("%s %d\n",sto[p],max1);
	
	for(i=0;i<=num;i++) if(max2<count[i]) {p=i;max2=count[i];}
	if(max2==0) return 0; 
	else
	{
	count[p]=0;
	printf("%s %d\n",sto[p],max2);
	}
	
	for(i=0;i<=num;i++) if(max3<count[i]) {p=i;max3=count[i];}
	if(max3==0) return 0;
	else
	{
	count[p]=0;
	printf("%s %d\n",sto[p],max3);
	}
	
	for(i=0;i<=num;i++) if(max4<count[i]) {p=i;max4=count[i];}
	if(max4==0) return 0;
	else
	{
	count[p]=0;
	printf("%s %d\n",sto[p],max4);
	}
	
	for(i=0;i<=num;i++) if(max5<count[i]) {p=i;max5=count[i];}
	if(max5==0) return 0;
	else 
	{ 
	count[p]=0;
	printf("%s %d\n",sto[p],max5);
	}
	return 0;
}

总结与心得:
综合性实验主要考查本学期c语言所学语法的综合运用,灵活多变,思维量不大,实验过程中细节和注意点较多。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值