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$
讲真我觉得这个标程一般