文本文件单词统计

问题描述:

假设有如下的英文文本文档:(文件名是:Happiness.txt)

What Is Happiness

Most of us probably don’t believe we need a formal definition of happiness; we know it

when we feel it, and we often use the term to describe a range of positive emotions,

including joy, pride, contentment, and gratitude.

But to understand the causes and effects of happiness, researchers first need to define

it. Many of them use the term interchangeably with “subjective well-being,” which they

measure by simply asking people to report how satisfied they feel with their own lives and

how much positive and negative emotion they’re experiencing. In her 2007 book The How

of Happiness, positive psychology researcher Sonja Lyubomirsky elaborates, describing

happiness as “the experience of joy, contentment, or positive well being, combined with a

sense that one’s life is good, meaningful, and worthwhile.”

That definition resonates with us here at Greater Good: It captures the fleeting positive

emotions that come with happiness, along with a deeper sense of meaning and purpose in

life and suggests how these emotions and sense of meaning reinforce one another.

设计 C 或 C++程序,统计在这样的英文文本文件中,出现了多少个单词(不区分大小写),每个单词出现了几次。连续的英文字符都认为是单词(不包括数字),单词之间用空格或标点符号分隔。

设计需求及分析:

要统计英文文本文件中出现了哪些单词,就要从文件中读取字符,读取出来的连续英文字符认为是一个单词,遇空格或标点符号单词结束。

使用线性表记录单词以及每个单词出现的次数。线性表中的单词按字典顺序存储。

线性表的顺序存储结构如下:(必须使用如下定义的存储结构,否则无效

#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量

#define LISTINCREMENT 10 //线性表存储空间的分配增量

typedef struct{

char word[21] //存储单词,不超过 20 个字符

int count; //单词出现的次数

} ElemType;

typedef struct{

ElemType *elem; //存储空间基址

int length; //当前长度

int listsize; //当前分配的存储容量

} SqList;

功能设计:

(一)实现顺序表的基本操作(必须使用下面给定的函数名和参数表,否则无效)

⑴顺序表的初始化:InitList(SqList &L)

⑵顺序表上查找指定的单词:LocateElem(SqList &L,char *s) 若找到,单词的出现次数增 1,返回 0,否则返回该单词的插入位置。

⑶在顺序表上插入新的单词:InsertList(SqList &L,int i,char *s)要求按字典顺序有序。新单词的出现次数为 1。

⑷输出顺序表上存储的单词统计信息:PrintList(SqList &L)输出文件中每个单词出现的次数以及文件中总的单词数(可输出到文件中)。

(二)统计单词数

统计过程如下:

(1)输入要统计单词的文本文件名,打开相应的文件;

(2)初始化顺序表;

(3)从文本文件中读取字符,直到文件结束。具体描述如下:

while (读文件没有结束)

{

过滤单词前的非字母字符;

读取一个单词,以字符串形式存储在一个字符数组中;

在线性表中查找该单词,若找到,单词的出现次数加 1,否则返回其插入位置;

上一步中,若没找到,则进行插入操作;

处理下一个单词。

}

 测试数据:

将上述给定的英文文档写入文本文件:Happiness.txt 作为测试数据文件。

 

程序代码:

#include 
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
#define LISTINCREMENT 10 //线性表存储空间的分配增量
typedef struct{
	char word[21];//存储单词,不超过 20 个字符
	int count; //单词出现的次数
} ElemType;
typedef struct{
	ElemType *elem; //存储空间基址
	int length; //当前长度
	int listsize; //当前分配的存储容量
} SqList;

//顺序表的初始化 
int InitList(SqList *L){
	//构造一个空的线性表L
	L->elem=(ElemType*)malloc(LIST_INIT_SIZE*sizeof(ElemType));
	if(!L->elem) exit(OVERFLOW);//存储分配失败 
	L->length = 0;//空表长度为0 
	L->listsize =  LIST_INIT_SIZE;//初始化容量 
	return 1;
}
//顺序表上查找指定的单词
int LocateElem(SqList *L,char *word){
	int low, mid, high;
	low = 0; high = L->length-1 ;//定义顺序表的最高和最低位置 
	while (low<=high)//进行二分查找 
	{
		mid = (low + high) / 2;
		// 使用strcmp()比较 两个单词是否相等 
		if (strcmp(word, L->elem[mid].word) == 0) {
			L->elem[mid].count++; return 0;
		}
		else if (strcmp(word, L->elem[mid].word) < 0)
			high = mid - 1;
		else
			low = mid + 1;
	}
	//返回该单词的插入位置
	return low + 1;
}
//在顺序表上插入新的单词 
int InsertList(SqList *L,int i,char *word){
	int j;
	ElemType *base; //定义一个指针用于查询 
	if(L->length>=L->listsize){
		//使用 realloc函数扩大内存块 
		base=(ElemType*)realloc(L->elem,(L->listsize+LISTINCREMENT)*sizeof(ElemType));
		if(base==NULL)
			return 0;
		//线性表存储空间增加10 
		L->listsize=L->listsize+LISTINCREMENT;
		L->elem=base; 
	}
	for (j = L->length; j >= i; j--)
		L->elem[j] = L->elem[j-1];
	//将传进来的单词复制到顺序表 
	strcpy(L->elem[i-1].word,word);
	//将新传进来的单词次数置为一 
	L->elem[i - 1].count = 1;
	//顺序表长度+1 
	L->length++;
	return 1;
}
//输出顺序表上存储的单词统计信息
int PrintList(SqList *L,int num){
	int i;
	int no=num;
	//定义文件指针 
	FILE *fw;
	//新建一个 lcc.txt文件用于存放结果; 
	fw=fopen("c:\\lcc.txt","w");
	
	for (i = 0; i < L->length; i++) {
	//磁盘文件的写入 
	fprintf(fw,"%s  %d\n",L->elem[i].word,L->elem[i].count);
	} 
	fprintf(fw,"单词数量%d",num);
	//关闭磁盘文件 
	fclose(fw);
	return 1;
}

int main(){
	SqList L;
	char word[21],ch,filename[30],filename1[50];
	int num=0,j=0,mark=0,i;
	//创建文件指针 
	FILE *fp;
	//初始化顺序表 
	InitList(&L);
	//读入将要扫描的文件名 
	scanf("%s",filename);
	//将文件路径+文件名赋值给 filename1
	sprintf(filename1,"C:\\%s.txt",filename);
	getchar();//取得文件路径及文件名 
	if((fp=fopen(filename1,"r"))==NULL){//判断文件是否存在 
		printf("文件路径错误\n");
		getchar();
		exit(0);
	}
	ch=fgetc(fp);
	//从文本文件中读取字符,直到文件结束。 
	while (ch != EOF){
		//过滤单词前的非字母字符; 
		if (ch >= 'a'&&ch <= 'z'||ch>='A'&&ch<='Z') {
			//将大小写合并(题中不区分大小写) 
			ch = ch >= 'A'&&ch <= 'Z' ? ch + 32 : ch; 
			word[j++] = ch;
			//标识单词 
			mark = 1;
		}else { 
			if (mark == 1)
			{
				word[j] = '\0';
				mark = 0;
				num++;
				j = 0;
				//查找单词 
				i = LocateElem(&L, word);
				if (i > 0)
				InsertList(&L,i,word);
			}
		}
		//从磁盘中读取一个字符并返回 
		ch = fgetc(fp);
	}
	//写入文件 
	PrintList(&L,num);
	printf("扫描成功\n");
    return 0;
}

运行结果:

源文件Happiness.txt放在c盘根目录下,如下图:

文本文件单词统计_第1张图片

 运行:

文本文件单词统计_第2张图片

 运行后在C盘根目录下会出现一个lcc.txt,如下图:

文本文件单词统计_第3张图片

 打开为运行结果,如下:

a  4
along  1
and  9
another  1
as  1
asking  1
at  1
being  2
believe  1
book  1
but  1
by  1
captures  1
causes  1
combined  1
come  1
contentment  2
deeper  1
define  1
definition  2
describe  1
describing  1
don  1
effects  1
elaborates  1
emotion  1
emotions  3
experience  1
experiencing  1
feel  2
first  1
fleeting  1
formal  1
good  2
gratitude  1
greater  1
happiness  6
her  1
here  1
how  4
in  2
including  1
interchangeably  1
is  2
it  4
joy  2
know  1
life  2
lives  1
lyubomirsky  1
many  1
meaning  2
meaningful  1
measure  1
most  1
much  1
need  2
negative  1
of  9
often  1
one  2
or  1
own  1
people  1
positive  5
pride  1
probably  1
psychology  1
purpose  1
range  1
re  1
reinforce  1
report  1
researcher  1
researchers  1
resonates  1
s  1
satisfied  1
sense  3
simply  1
sonja  1
subjective  1
suggests  1
t  1
term  2
that  3
the  6
their  1
them  1
these  1
they  3
to  4
understand  1
us  2
use  2
we  4
well  2
what  1
when  1
which  1
with  6
worthwhile  1
单词数量176

 

注意:

测试时注意输入的是不带文件后缀的文件名,并且应该将文件放在代码中规定的位置,若读者不能很好的理解本节的内容,课先参考一下以下几个基础内容:

  1. https://blog.csdn.net/qq_42410605/article/details/94429603
  2. https://blog.csdn.net/qq_42410605/article/details/94433697
  3. https://blog.csdn.net/qq_42410605/article/details/94457811

本节内容涉及数据结构的内容我将会在后续更新。

说明:

 

  1. #include头文件也叫万能头文件,其包含常用的头文件,如果你记不得用到哪些头文件或者想要代码看起来简洁一点可以使用它作为头文件。
  2. 命名空间 using namespace std; 尽量不要使用,命名空间一般和cin,cout一同使用,在考试或者上机时,本人不建议使用cin和cout,因为它们在输入输出大量数据时表现非常糟糕,有时候等不到数据输入完成就会超时,在某些特定的时刻必须使用命名空间,例如使用string时,想要使用string ,必须要用命名空间 std,string 是标准库,C++标准引入了命名空间namespace,标准库的空间是std。

 

你可能感兴趣的:(#,算法笔记)