文本文件单词的检索技术(代码实现及实验准备)

这里写目录标题

实验准备

项目目标和主要内容
构建文本文件单词的检索与计数,采用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;
        }
        }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值