实验准备
项目目标和主要内容
构建文本文件单词的检索与计数,采用vs平台,使用c++语言
项目的主要功能
文本文件中每个单词不包含空格且不跨行,单词由字符序列构成且区分大小写,统计给定单词在文本文件中出现的总次数,检索输出的某个单词出现在文本中的行号、在该行中出现的位置。
设计数据量大的文本,进行子串的查询处理,分析算法运行的时间效率,对所有输出的匹配位置结果进行验证,以证明算法设计和实现的正确性。
用朴素模式匹配算法或KMP算法实现字符串定位;
可正确读取,保存文本;
代码实现
#include<iostream>
#include<string.h>
#include<fstream>
#pragma warning(disable:4996)
#include<conio.h>//catch() 任意键继续
#include<iomanip>
#include<string>
#include<algorithm>
#include<sstream>
using namespace std;
#define MAXSIZE 1000
struct str {
char data[MAXSIZE];
int length;
};
/*
* 朴素模式匹配(暴力匹配)
*/
int simple(str s, str goal, int begin)
{
int i = begin; //指定位置开始查找
int j, k, m, n;
m = goal.length; //模式串长度赋m
n = s.length; //目标串长度赋n
for (;i < n;i++)
{
j = 0;
k = i; //目标串起始位置i送入k
while (j <= m && s.data[k] == goal.data[j])
{
k++;
j++; //继续下一个子符的比较
}
if (j == m) //若相等,则说明找到匹配的子串,返回匹配位置i
return i + 1; //否则从下一个位置重新开始比较
}
return -1;
}
/*
* 查找的单词的最长相等前后缀
* next[i]=j,含义是:下标为i 的字符前的字符串最长相等前后缀的长度为j。
*/
int* GetNext(str goal_s)
{
//由模式串t求出next值
int gls = goal_s.length;//单词长度
int next[MAXSIZE];//目标单词的next数组
int j = 0, k = -1;
next[0] = -1;//第一个字符前无字符串,给值-1
while (j < gls)
{
if (k == -1 || goal_s.data[j] == goal_s.data[k])
{
j++;k++;
if (goal_s.data[j] != goal_s.data[k])
//这里的t.data[k]是t.data[j]处字符不匹配而会回溯到的字符
//为什么?因为没有这处if判断的话,此处代码是next[j]=k;
//next[j]不就是t.data[j]不匹配时应该回溯到的字符位置嘛
next[j] = k;
else
next[j] = next[k];
//
//此时nextval[j]的值就是就是t.data[j]不匹配时应该回溯到的字符的nextval值
//即字符不匹配时回溯两层后对应的字符下标
}
else k = next[k];
//next[k]的值代表的是下标为k的字符前面的字符串最长相等前后缀的长度
//也表示该处字符不匹配时应该回溯到的字符的下标
//这个值给k后又进行while循环判断,此时t.data[k]即指最长相等前缀后一个字符
}
return next;
}
/*KMP算法
*begin为开始搜索的位置
*/
int KMP(str s, str goal_s, int* next, int begin)
{
int sl = s.length;
int gsl = goal_s.length;//要查找的字符长度
int i = begin;
int j = 0;
while (i < sl && j < gsl)
{
if (s.data[i] == goal_s.data[j] || j == -1)
{
i++;j++;
}
else j = next[j];
}
if (j >= gsl)
return(i - gsl + 1);
else
return(-1);//未找到
}
/*
* 对单行内容计数
* choose 选择匹配模式(1-朴素模式匹配 2-KMP)
* 返回次数
*/
int getIndexOfLine(str s, str goal_s, int line, int show = 0, int choose = 2) {
int gls = goal_s.length;//目标单词长度
int* next;
int index[20];
switch (choose)
{
case 1:
{
int result0 = simple(s, goal_s, 0);
if (result0 == -1) {
return -1;
}
int i = 0;
while (result0 != -1) {//搜索到一个后继续往后搜索,直到行末
index[i] = result0;
result0 = simple(s, goal_s, result0 + gls - 1);
i++;
}
break;
}
case 2:
{
next = GetNext(goal_s);//目标的next数组
int result = KMP(s, goal_s, next, 0);
if (result == -1) {
return -1;
}
int i = 0;
while (result != -1) {//搜索到一个后继续往后搜索,直到行末
index[i] = result;
result = KMP(s, goal_s, next, result + gls - 1);
i++;
}.
}
break;
}
int k = 0;
if (show == 1)
{
// k = 0;//记录个数
cout << "第" << line << "行:" << ' ';
while (index[k] > 0)
{
cout << index[k] << "\t";
k++;
}
cout << endl;
}
else {
while (index[k] > 0) {
k++;
}
}
return k;
}..
/*
* 文本内容查找某单词计数
* 返回总次数
*/
int readFileCount(str goal, int show, int choose)
{
int sum = 0;//记录总次数
int lsum = 0;//记录单行出现的次数
cout << "请输入文件的完整地址路径:" << endl;//(格式:E:\c\count.txt)
string name;
cin >> name;
string. a;//保存一行内容
ifstream in;
in.open(name);
int m = 0;//记录第几行
while (getline(in, a))
{
m++;
str tt;//转换成str
tt.length = a.length();
for (int i = 0;i < tt.length;i++) {
tt.data[i] = a[i];
}
lsum = getIndexOfLine(tt, goal, m, show, choose);
if (.lsum == -1) {//该行未出现
continue;
}
else {
sum = sum + lsum;
continue;
}
}
if (sum > 0) {
return sum;
}
else {
return 0;
}
}
/*
* 写文件
*/
void writeFile() {
system("cls");
int n;
string file_name;
cout << "请输入文本名称: ";
cin >> file_name;
cout << "请输入文本行数:";
cin >> n;
ofstream outfile;
outfit.le.open(("E://" + file_name + ".txt").c_str());
cout << "文件创建成功!" << endl;
cout << "请输入" << n << "行单词:" << endl;
string a;
for (int i = 0; i <= n; i++) {
getline(cin, a);
outfile << a << endl;
}
outfile.close();
cout << "单词本已生成!按任意键返回" << endl;
getch();
}
int main() {
cout. << "********************欢迎来到文本文件的检索********************" << endl;
cout << "--------------------------------------------------------------" << endl;
while (true)
{
cout << "--------------------------------------------------------------" << endl;
cout << "********1-创建文件********" << endl;
cout << "********2-单词检索********" << endl;
cout << "********3-单词计数********" << endl;
cout << "********4-退出 ********" << endl;
cout << "--------------------------------------------------------------" << endl;
cout << "请选择:" << endl;
int choose;
cin >> choose;
switch (choose)
{
case 1:
writeFile();
break;
case 2:
{
cout << "请输入要查找的内容:" << endl;
string t;
cin >> t;
str tt;
tt.length = t.length();
for (int i = 0;i < tt.length;i++) {
tt..data[i] = t[i];
}
int re = 2;
cout << "--------------------------------------------------------------" << endl;
cout << "请选择检索的算法:(1-朴素模式匹配 2-KMP)" << endl;
cout << "--------------------------------------------------------------" << endl;
int chioce;
cin >> chioce;
switch (chioce)
{
case 1:
re = 1;.
break;
case 2:
re = 2;
break;
default:
cout << "无效字符!" << endl;
break;
}
int sum = readFileCount(tt, 1, re);
if (sum == 0) {
cout << "未找到!" << endl;
}
else {
cout << "一共出现了:" << sum << "次" << endl;
}
}
break;
case 3:
{
cout << "请输入要查找的内容:" << endl;
string t;
cin >> t;
str tt;
tt.length = t.length();
for (int. i = 0;i < tt.length;i++) {
tt.data[i] = t[i];
}
int sum = readFileCount(tt, 0, 2);
if (sum == 0) {
cout << "未找到!" << endl;
}
else {
cout << "一共出现了:" << sum << "次" << endl;
}
}
break;
case 4:
exit(0);
break;
default:
cout << "输入无效!" << endl;
break;
}
}