前言
【问题描述】
文学研究人员需要统计某篇英文小说中某些形容词的出现次数和位置。试写一个实现这一目标的文字统计系统
【任务要求】
- 英文小说存于一个文本文件中。待统计的词汇集合要一次输入完毕,即统计工作必须在程序的一次运行之后就全部完成。程序的输出结果是每个词的出现次数和出现位置所在的行的行号,格式自行设计。待统计的“单词”在文本串中不跨行出现,它或者从行首开始,或者前置以一个空格符。
- 模式匹配要基于KMP算法。
【测试数据】
- 文本文件为testword.c
- 待统计的词集:if、else、for、while、return、void、int、char、typedef、struct
一、Kmp算法是什么?
建议大家先去看看这篇文章:
KMP算法详解-彻底清楚了(转载+部分原创) - sofu6 - 博客园 (cnblogs.com)
或者去b站找个kmp视频学习一下。
二、上代码
1.求nextval数组
void get_next(SString T,int nextval[]){
int i,k;
i=1,k=0;
next[1]=0;
while(i<T[0]){//T[0]储存的是字符串的长度,
if(k==0||T[i]==T[k]){
++i;
++k;
next[i]=k;
}
else{
k=next[k];//否则k只的值回溯
}
}
}
2.kmp算法
代码如下(示例):
int Index(SString S,SString T,int pos) //KMP算法
{
int i=pos,j=1;
while(i<=S[0]&&j<=T[0])
{
if(j==0||S[i]==T[j])
{
++i;
++j;
}
else
{
j=next[j];
}
}
if (j>T[0])
{
return (i-T[0]);
}
else
{
return 0;
}
}
3:求关键字的长度:
int length(SString str){
int i=1;
while(str[i]){
i++;
}
return i-1;
}
4:查找函数:
void find(char name[],SString keys) //查找函数,该函数是整个程序的重要部分,对于输入的每一个
{ //要查找的关键字,从小说文件中逐行读取字符串查找
SString text; //存放从小说文件读取的一行字符串
int i=1,j=0,k; //i用于存放行号,j用于存放列号,k用于输出格式的控制
int count=0;
FILE *fp;
fp=fopen(name,"r");
if (fp==NULL) //打开小说文件
{
printf("文件打开失败!\n");
exit(0);
}
keys[0]=length(keys); //求关键字的长度
get_next(keys,next); //求模式串(关键字)每一个字符对应的next值
int l;
printf("%s对应的next数组为:\n",&keys[1]);
for(l=1;l<=keys[0];l++){
printf("%d ",next[l]);
}
printf("\n");
printf("%s\n",&keys[1]); //打印关键字
while (!feof(fp)) //如果还没到小说文件末尾
{
k=0;
fgets(&text[1],MaxSize,fp); //从小说文件中读取一行字符串,存入text串中
//puts(&text[1]);
//printf("*******************************\n");
text[0]=length(text); //求读入的串的长度
j=Index(text,keys,j+1); //调用KMP算法,统计关键字在该行出现的位置,若匹配不成功则返回0
if (j!=0)
{
k++;
printf("row=%d,col=%d",i,j); //若匹配成功则打印行号和列号
}
while(j!=0) //若该行找到了关键字,则继续寻找看是否还能匹配成功
{
j=Index(text,keys,j+1); //调用KMP算法从刚找到的列号后一字符起匹配
if (j!=0)
{
k++;
printf(",%d",j);//若匹配成功,则打印列号
}
}
i++; //行号加1,在下一行中寻找
count=count+k;
if (k)
{
printf("\n"); //输出格式控制
}
}
fclose(fp);
if(count){
printf("%s共出现%d次\n",&keys[1],count);
}
else{
printf("No Found\n");
}
}
5:主函数:
int main()
{
char textname[20];//用于存放文本文件名;
SString inputwords[20];//用于存放要查询的关键字;
int n,i;
printf("请输入你所查询文字所在的文件名:\n");
gets(textname);//或者用scanf("%s",textname);
printf("请输入你要查询关键字的个数:\n");
scanf("%d",&n);
printf("请输入关键字:\n");
for(i=0;i<n;i++){
scanf("%s",&inputwords[i][1]);
}
printf("查询的结果如下:\n");
for(i=0;i<n;i++){
find(textname,inputwords[i]);
}
//for(i=0;i<n;i++){
//int len=length(inputwords[i]);
//printf("%s的长度为%d\n",inputwords[i],len);
//}
return 0;
}
6:注意事项:
如果大家要是从文本导入数据信息时一定要注意,在保存文本文档时把txt文件另存为,把下面的编码格式改为ANSI就可以了,它默认的是UTF-8!!!!!
7:所有代码:
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 1000//定义串的长度;
typedef char SString[MaxSize + 1];//定义一个字符数组,并取别名;
int next[MaxSize];//用于kmp算法,主要存储每个字符的前后缀的值;
int length(SString str){
int i=1;
while(str[i]){
i++;
}
return i-1;
}
void get_next(SString T,int nextval[]){
int i,k;
i=1,k=0;
next[1]=0;
while(i<T[0]){//T[0]储存的是字符串的长度,
if(k==0||T[i]==T[k]){
++i;
++k;
next[i]=k;
}
else{
k=next[k];//否则k只的值回溯
}
}
}
int Index(SString S,SString T,int pos) //KMP算法
{
int i=pos,j=1;
while(i<=S[0]&&j<=T[0])
{
if(j==0||S[i]==T[j])
{
++i;
++j;
}
else
{
j=next[j];
}
}
if (j>T[0])
{
return (i-T[0]);
}
else
{
return 0;
}
}
void find(char name[],SString keys) //查找函数,该函数是整个程序的重要部分,对于输入的每一个
{ //要查找的关键字,从小说文件中逐行读取字符串查找
SString text; //存放从小说文件读取的一行字符串
int i=1,j=0,k; //i用于存放行号,j用于存放列号,k用于输出格式的控制
int count=0;
FILE *fp;
fp=fopen(name,"r");
if (fp==NULL) //打开小说文件
{
printf("文件打开失败!\n");
exit(0);
}
keys[0]=length(keys); //求关键字的长度
get_next(keys,next); //求模式串(关键字)每一个字符对应的next值
int l;
printf("%s对应的next数组为:\n",&keys[1]);
for(l=1;l<=keys[0];l++){
printf("%d ",next[l]);
}
printf("\n");
printf("%s\n",&keys[1]); //打印关键字
while (!feof(fp)) //如果还没到小说文件末尾
{
k=0;
fgets(&text[1],MaxSize,fp); //从小说文件中读取一行字符串,存入text串中
//puts(&text[1]);
//printf("*******************************\n");
text[0]=length(text); //求读入的串的长度
j=Index(text,keys,j+1); //调用KMP算法,统计关键字在该行出现的位置,若匹配不成功则返回0
if (j!=0)
{
k++;
printf("row=%d,col=%d",i,j); //若匹配成功则打印行号和列号
}
while(j!=0) //若该行找到了关键字,则继续寻找看是否还能匹配成功
{
j=Index(text,keys,j+1); //调用KMP算法从刚找到的列号后一字符起匹配
if (j!=0)
{
k++;
printf(",%d",j);//若匹配成功,则打印列号
}
}
i++; //行号加1,在下一行中寻找
count=count+k;
if (k)
{
printf("\n"); //输出格式控制
}
}
fclose(fp);
if(count){
printf("%s共出现%d次\n",&keys[1],count);
}
else{
printf("No Found\n");
}
}
int main()
{
char textname[20];//用于存放文本文件名;
SString inputwords[20];//用于存放要查询的关键字;
int n,i;
printf("请输入你所查询文字所在的文件名:\n");
gets(textname);//或者用scanf("%s",textname);
printf("请输入你要查询关键字的个数:\n");
scanf("%d",&n);
printf("请输入关键字:\n");
for(i=0;i<n;i++){
scanf("%s",&inputwords[i][1]);
}
printf("查询的结果如下:\n");
for(i=0;i<n;i++){
find(textname,inputwords[i]);
}
//for(i=0;i<n;i++){
//int len=length(inputwords[i]);
//printf("%s的长度为%d\n",inputwords[i],len);
//}
return 0;
}
总结
如果对读者有帮助大家就动动小手点个赞再走吧!谢谢啦。