SCAU程序设计在线实训平台_实验_高级语言程序设计_综合性实验

1109 综合实验:文件操作与字符处理

Description

在当前目录中存在文件名为"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

代码实现① (未完成20201214)
#include "stdio.h"
#include "math.h"
#include "string.h"
#include "stdlib.h"

struct oneword{
    char cha[20];
    int num;
}words[10000],temp;

void main()
{
    char ch;
    int i=0,j=0;
    FILE *fp;
    fp = fopen("case1.in","r");

    while((ch=fgetc(fp))!=EOF){
        if('A'<=ch && ch<= 'Z'){        //大写
            ch+=32;
            words[i].cha[j]=ch;
            j++;    //下一个字母
        }

        else if('a'<=ch && ch<= 'z'){       //小写
            words[i].cha[j]=ch;
            j++;    //下一个字母
        }

        else if(ch='-'){    //连接符或空格

            if((ch=fgetc(fp))=='\n'){   //如果连接符后是换行
                continue;
            }
            else{
                j=0;//如果空格后是字母
                if('A'<=ch && ch<= 'Z'){

                    ch+=32;
                    i++;
                    words[i].cha[j]=ch;
                    j++;
                }
                else if('a'<=ch && ch<= 'z'){
                    i++;
                    words[i].cha[j]=ch;
                    j++;
                }

            }

        }
        else{       //啥也不是则到下一个字符
            continue;
        }

    }
    int wordnumber =i;
    char str[20];
    for(int k=0;k<=wordnumber;k++){
        printf("%s ",words[k].cha);
    }
    printf("\n");

    for(int i=0;i<wordnumber-1;i++){
        for(int j=0;j<wordnumber-1-i;j++){
            if(strcmp(words[j].cha,words[j+1].cha)>0){
                strcpy(temp.cha,words[j].cha);
                strcpy(words[j].cha,words[j+1].cha);
                strcpy(words[j+1].cha,temp.cha);
            }
        }
    }

    for(int k=0;k<=wordnumber;k++){
        printf("%s ",words[k].cha);
    }
}
代码实现② (第一次通过评测20201215)
$block1$
#include <ctype.h>	//C 标准库的 ctype.h 头文件提供了一些函数,可用于测试和映射字符。
struct word{
    char cha[20];
    int num;
}words[10000],tmp;
$end1$
$block2$
    //打开文件
    FILE *fp;
    fp=fopen("case1.in","r");
    char str[10000*20]={0},files[10000*20]={0},ch;
    //将文件中内容读取到files字符串中
    int node=0;
    while((ch=fgetc(fp))!=EOF){
        files[node]=ch;
        node++;
    }
    //puts(files);
    //去除所有标点并转小写,储存到str中进一步处理
    node=0;     //原字符串下标,str下标
    int i=0;
    while(node<strlen(files)){
        if(isalpha(files[node])){    //字母或空格
            if(files[node]>='A'&&files[node]<='Z')files[node]+=32;  //大写转小写
            str[i]=files[node];
            i++;
        }
        else if(files[node]=='-'&&files[node+1]=='\n')node++;   //如果是换行连接符
        else if(!isalpha(files[node])&&isalpha(files[node+1])){     //标点后紧接字母的则当成空格处理
            str[i]=' ';
            i++;
        }
        node++;
    }
    str[i]=' ';     //最后补一个空格方便后续处理
    //puts(str);  //输出处理后的字符串
    //单词处理
    i=0;
    int wordcode=0,wordchacode;     //单词编号,单词字符串下标
    while(str[i]==' ')i++;  //跳过前置空格
    while(str[i+1]!='\0'){      //进入单词处理
        wordchacode=0;
        char aword[20]={0};
        while(str[i]==' ')i++;  //跳过单词间间空格
        while(str[i]!=' '){     //遇到单词第一个字母
            aword[wordchacode]=str[i];      //将整个单词录入到aword中
            wordchacode++;      //单词字符串下标+1
            i++;
        }
        int j=0;    //已存在单词下标
        for(;j<wordcode;j++){       //遍历结构体数组检查该单词是否已经录入
            if(strcmp(aword,words[j].cha)==0){
                words[j].num++;     //若该单词存在则数量+1
                break;
            }
        }
        if(j==wordcode){    //如果遍历完结构体数组尚未发现有重复
            words[j].num=1;     //新单词初始数量=1
            strcpy(words[j].cha,aword);     //录入一个单词
            wordcode++;     //结构体内单词编号(数量)+1
        }
    }
    //按字母顺序冒泡排序
    for(int i=0;i<wordcode-1;i++){
        for(int j=0;j<wordcode-i-1;j++){
            if(strcmp(words[j].cha,words[j+1].cha)>0){
                tmp=words[j];
                words[j]=words[j+1];
                words[j+1]=tmp;
            }
        }
    }
    //按数量多少冒泡排序
    for(int i=0;i<wordcode-1;i++){
        for(int j=0;j<wordcode-i-1;j++){
            if(words[j].num<words[j+1].num){
                tmp=words[j];
                words[j]=words[j+1];
                words[j+1]=tmp;
            }
        }
    }
    //输出
    if(wordcode>5)wordcode=5;   //若超过五个则只输出5个
    for(int k=0;k<wordcode;k++){
        printf("%s %d\n",words[k].cha,words[k].num);
    }
    fclose(fp);
$end2$

代码实现③(使用函数-指针优化,增加可读性20201217)
#include "stdio.h"
#include "math.h"
#include "string.h"
#include "stdlib.h"
#include <ctype.h>	//C 标准库的 ctype.h 头文件提供了一些函数,可用于测试和映射字符。
//结构体数组
struct word{
    char cha[20];
    int num;
}words[10000],tmp;

//读取文件到字符串
void fileToStr(FILE *file,char *str){       //文件指针,字符串指针
    char ch;
    while((ch=fgetc(file))!=EOF){
        *str=ch;
        str++;  //指向下一个储存位置
    }
}

//处理符号函数
void symbol(char *origin,char *after){      //待处理字符串指针,处理结果输出字符串指针

    while(*origin!='\0'){
        if(isalpha(*origin)){    //是字母
            if(*origin>='A'&&*origin<='Z')*origin+=32;  //大写转小写
            *after=*origin;     //储存
            after++;    //指向下一个储存位置
        }

        else if(*origin=='-'&&*(origin+1)=='\n')origin++;   //如果是换行连接符,则指向下一个字符

        else if(!isalpha(*origin)&&isalpha(*(origin+1))){     //标点后紧接字母的为单词分隔符,则当成空格处理
            *after=' ';     //储存
            after++;    //指向下一个储存位置
        }

        origin++;   //指向下一个字符
    }
    *after=' ';     //最后补一个空格方便后续单词分割处理
}

//检查单词函数
void countWords(char *oneword,struct word *wordlist){   //输入一个单词指针,和结构体数组指针

    while(*wordlist->cha!='\0'){       //遍历结构体数组检查该单词是否已经录入
        if(strcmp(oneword,wordlist->cha)==0){
            wordlist->num++;     //若该单词存在则数量+1
            //printf("%s--%d\n",wordlist->cha,wordlist->num);
            break;
        }
        wordlist++;
    }

    if(*wordlist->cha=='\0'){    //如果遍历完结构体数组尚未发现有重复
        strcpy(wordlist->cha,oneword);     //录入一个单词
        wordlist->num=1;     //新单词初始数量=1
        //printf("%s--%d\n",wordlist->cha,wordlist->num);
    }
}

//打印结构体
void printstruct(struct word *wordlist){    //输入一个结构体数组指针
    int num=0;
    while(*wordlist->cha!='\0'&&num<5){
        printf("%s %d\n",wordlist->cha,wordlist->num);
        wordlist++;
        num++;
    }
}

//按照单词字典升序,排序结构体数组
void alphrank(struct word *wordlist,int wordnum){
    for(int i=0;i<wordnum-1;i++){
        for(int j=0;j<wordnum-i-1;j++){
            if(strcmp(wordlist[j].cha,wordlist[j+1].cha)>0){
                tmp=wordlist[j];
                wordlist[j]=wordlist[j+1];
                wordlist[j+1]=tmp;
            }
        }
    }
}

//按照单词数量降序,排序结构体数组
void numrank(struct word *wordlist,int wordnum){
    for(int i=0;i<wordnum-1;i++){
        for(int j=0;j<wordnum-i-1;j++){
            if(words[j].num<words[j+1].num){
                tmp=wordlist[j];
                wordlist[j]=wordlist[j+1];
                wordlist[j+1]=tmp;
            }
        }
    }
}


main (){
    //打开文件
    FILE *fp;
    fp=fopen("case1.in","r");


    char str[10000*20]={0},files[10000*20]={0};


    //将文件中内容读取到files字符串中
    fileToStr(fp,files);
    //puts(files);   //输出读入的字符串

    //处理符号后保存到str中
    symbol(files,str);
    //puts(str);  //输出处理后的字符串


    //单词处理
    int i=0;    //字符串下标
    while(str[i]==' ')i++;  //跳过前置空格

    while(str[i+1]!='\0'){      //进入单词处理

        int wordchacode=0;  //一个单词的第n个字母下标
        char aword[20]={0};

        while(str[i]==' ')i++;  //跳过单词间间空格

        while(str[i]!=' '){     //遇到单词第一个字母,循环将整个单词录入到aword中
            aword[wordchacode]=str[i];
            wordchacode++;      //下一个字符
            i++;
        }

        countWords(aword,words);    //检查该单词
    }


    //统计总单词个数
    int wordnum=0;
    while(*words[wordnum].cha!='\0')wordnum++;


    //排序
    alphrank(words,wordnum);
    numrank(words,wordnum);

    //输出
    printstruct(words);
    fclose(fp);
}

优化以后更长了= =

系统标程
$block1$
#include<ctype.h>
#include<malloc.h>
#define LEN sizeof(struct c_word)
int num=0;//统计不同单词个数
struct c_word //用结构体变量存储读入的单词
{
	char word[30];//存储读入单词
	int count;//统计相同单词个数
	struct c_word *next;
};
/*定义函数插入新单词*/
struct c_word *insert(struct c_word *head,struct c_word *new_word)
{
	struct c_word *p0=new_word,*p1=head,*p2;
	int n;
         if(strlen(new_word->word)<1) return head;
	if(head==NULL) //考虑到第一次添加新单词的情况
	{
		head=p0;p0->next=NULL;
		p0->count=1;num++; //单词数为1
	}
	else
	{ 
		while((n=strcmp(p0->word,p1->word))>0&&p1->next!=NULL) 
			/*按字典顺序插入*/
		{
			p2=p1;
			p1=p1->next;
		}
		if(n==0)
			++p1->count; //读入的单词已出现过
		else   //在适当的位置添加新单词
			if(n<0)
			{
				if(head==p1) head=p0;/*插到原来第一个节点之前*/
				else p2->next=p0;/*插到p2指向节点后*/
				p0->next=p1;
				p0->count=1;
				num++; //不同单词数加1
			}
			else //插到最后的节点后
			{ 
				p1->next=p0;
				p0->next=NULL;
				p0->count=1;
				num++; //不同单词数加1
			}
	}
	return head;
}
void print(struct c_word *head)
{
	int i,max;
	struct c_word *p1,*p2;
	if(num<5) //不足5个单词时,按序输出全部单词
		while(head!=NULL)
		{
			printf("%s %d\n",head->word,head->count);
			head=head->next;
		}
	else
		for(i=0;i<5;i++) //输出出现次数最多的前5个单词及其出现次数
		{
			p1=head;
			p2=head;
			max=p1->count;
			while(p1->next!=NULL)
			{
				if(p1->count>max) 
				{
					max=p1->count;
					p2=p1;
				}
				p1=p1->next;
			}
			printf("%s %d\n",p2->word,p2->count);
			p2->count=0; //将已输出的单词出现次数清0,以免重复计算
		}
}
$end1$
$block2$
FILE *fp;
	int i=0;
	char ch;
	struct c_word *new_word=(struct c_word *)malloc(LEN); //为读入单词创建新节点
	struct c_word *head=NULL;
	if((fp=fopen("case1.in","r"))==NULL) //打开文件,若失败则输出信息后退出程序
	{
		printf("cannot open file\n");
		return 0;
	}
	ch=fgetc(fp);
	while(!islower(ch)&&!isupper(ch)) /*去掉第一个单词前的标点*/
		ch=fgetc(fp);
	while(ch!=EOF) //读入字符,遇到EOF后结束
	{
		if(ch=='-') //判断当前字符是否行末连字符
		{
			ch=fgetc(fp);
			if(ch=='\n') //遇到行末连字符,继续读入字符
			{
				ch=fgetc(fp);
				continue;
			}
			new_word->word[i]='\0';i=0;
			head=insert(head,new_word);
			new_word=(struct c_word *)malloc(LEN);
		}
		if(ispunct(ch)||isspace(ch)||isdigit(ch)) //判断当前字符是否标点,空格,数字
		{
			ch=fgetc(fp);//读入下一字符
			if(ispunct(ch)||isspace(ch)||isdigit(ch)) //是就跳到下次循环
				continue;
			new_word->word[i]='\0';i=0;   //单词末加空操作符并把i清0
			head=insert(head,new_word); //插入新单词
			new_word=(struct c_word *)malloc(LEN);
		}
		else
		{
			new_word->word[i++]=tolower(ch); //添加新字母
			ch=fgetc(fp);
			if(ch==EOF)
			{
               new_word->word[i]='\0';i=0;   
			   head=insert(head,new_word);
			}
		}
	}
	print(head); //输出结果
	fclose(fp); //关闭文件
$end2$

讲真我觉得这个标程一般

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值