C++文件关键词快速定位出现的行号实现高效搜索

 更新时间:2023年10月15日 15:01:46   作者:ysji  
这篇文章主要为大家介绍了C++文件关键词快速定位出现的行号实现高效搜索,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

博主刚开始学习c++,前段时间老师布置了c++的一个作业:

给定两个文件(一个源文件text4search.txt,一个文件keywords.txt包含需要在源文件中搜索的关键词),要求输出keywords.txt中每个关键词在源文件中出现的行号。

举个例子,如果keywords.txt中有一个关键词是c++,在text4search.txt中第1,7,9,43,543,586,2445行都出现了c++,那么应该输出c++:{1 7 9 43 543 586 2445 }

完整版代码

(代码已在vscode c++11标准运行成功)

#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
// 报错函数
void error(const char *p, const char *p2 = "") {
    std::cerr << p << ' ' << p2 << std::endl;
    std::exit(1);
}
map<string, vector<int>> keyCount(ifstream &inputFile, vector<string> &keywords) {
    map<string, vector<int>> resultMap;
    string line;
    int lineNum = 0;
    while (getline(inputFile, line)) {
        ++lineNum;
        // 读入文件的每一行
        std::istringstream sin(line);
        string word;
        //每行单词逐个检查是不是在keywords里面出现,而不是统计keyword在一行中出现的次数
        //这样不用单独写一个函数统计一行中某个关键词出现次数,也能够出现一次关键词就压入行号一次
        while (sin >> word) {
            auto it = find(keywords.begin(), keywords.end(), word);
            if (it != keywords.end()) {
                resultMap[word].push_back(lineNum);
            }
        }
    }
    return resultMap;
}
int main() {
    // 建立三个文件流对象并关联相应文件,注意这里大家要修改为自己的文件路径(或者使用命令行输入)
    std::ifstream fin1;
    fin1.open("D:/University/Code/cpp_vscode/lab4/keywords.txt"); // 和keywords.txt建立关联
    if (!fin1) {
        error("cannot open input file", "D:/University/Code/cpp_vscode/lab4/keywords.txt");
    }
    std::ifstream fin2;
    fin2.open("D:/University/Code/cpp_vscode/lab4/text2search.txt"); // 和text2search.txt建立关联
    if (!fin2) {
        error("cannot open input file", "D:/University/Code/cpp_vscode/lab4/text2search.txt");
    }
    std::ofstream fout;
    fout.open("D:/University/Code/cpp_vscode/lab4/result.txt"); // 和result.txt建立关联
    if (!fout) {
        error("cannot open output file", "D:/University/Code/cpp_vscode/lab4/result.txt");
    }
    // 将keywords存入keys这个字符串向量中(用fin1)
    vector<string> keys;
    string s;
    while (fin1 >> s) {
        keys.push_back(s);
    }
    fin1.close();
    // 利用fin2和keys产生结果map
    map<string, vector<int>> result = keyCount(fin2, keys);
    fin2.close();
    //输出,由于map会自动按照字典序排序,而行号也是按照升序逐行检测,因此输出不用再排序
    map<string, vector<int>>::iterator it1 = result.begin();
    while (it1 != result.end()) {
        fout << it1->first << " : " << "{";
        //it1->second是vector<int>类型,不能直接用fout输出
        for (const auto &it2 : it1->second) {
            fout << it2 << ",";
        }
        fout << "}" << endl;
        it1++;
    }
    fout.close();
    system("pause");
    return 0;
}

下面结合代码讲一讲我的思路。

这道题的难点在于如何选取正确、高效的存储方法和搜索方法:

显然我们不能简单的挨个读取text中的单词,找到一个关键词就输出一个行号——这样输出的行号是混乱的。

基本思路

  • 采用vector<string>储存所有keywords;
  • 采用map<string,vector<int>>储存每个关键词到所出现行号的映射(由于关键词出现的行号有多个,因此采用vector<int>储存行号组成的整数型向量)

具体代码

首先,这里涉及到文件的输入输出,肯定是要用到<fstream>的,然后自定义文件输入输出流对象并链接到对应的文件:

// 建立三个文件流对象并关联相应文件,注意这里大家要修改为自己的文件路径(或者使用命令行输入)
    std::ifstream fin1;
    fin1.open("D:/University/Code/cpp_vscode/lab4/keywords.txt"); // 和keywords.txt建立关联
    if (!fin1) {
        error("cannot open input file", "D:/University/Code/cpp_vscode/lab4/keywords.txt");
    }
    std::ifstream fin2;
    fin2.open("D:/University/Code/cpp_vscode/lab4/text2search.txt"); // 和text2search.txt建立关联
    if (!fin2) {
        error("cannot open input file", "D:/University/Code/cpp_vscode/lab4/text2search.txt");
    }
    std::ofstream fout;
    fout.open("D:/University/Code/cpp_vscode/lab4/result.txt"); // 和result.txt建立关联
    if (!fout) {
        error("cannot open output file", "D:/University/Code/cpp_vscode/lab4/result.txt");
    }

用文件输入流对象fin每次读入text中的一行,再用字符串输入流对象sin逐个读入该行的单词:

int lineNum = 0;
    //读入文件的每一行
    while (getline(inputFile, line)) {
        ++lineNum;
        std::istringstream sin(line);//新建sin准备读入每行中的单词

接下来,我们的关键点在于,如何用比较好的方法搜索并储存好每个关键词出现的行号呢?
一般而言,有两种搜索思路:

  • 每次读取一个keyword,在text全文中搜索这个keyword在哪些行出现了,记录行号;
  • 每次读取text中的一行,再逐个读取这一行中的每个词,最后搜索这个词是不是出现在keywords.txt中,如果出现,则记录该行的行号;

那么,哪一种搜索方法更好更高效呢?显然是第二种。第一种方法思路简单,但每次搜索全文的代价太高。以下是我采用第二种搜索的思路的代码:

//sin读入每行中的每个单词
while (sin >> word) {
            //使用find函数和迭代器搜索每个sin读入的单词是否出现在keywords这个vector中
            auto it = find(keywords.begin(), keywords.end(), word);
            if (it != keywords.end()) {
                //如果找到了,那么将这个关键词对应的行号存入map中
                resultMap[word].push_back(lineNum);
            }

走到这里,已经基本成功啦!最后只需要把我们的答案正确输出,这里我使用迭代器it1输出map中的关键词,由于map中的value值实际是vector类型,不能简单使用it1->second输出,因此我们再定义一个it2输出vector<int>中的内容

map<string, vector<int>>::iterator it1 = result.begin();
    while (it1 != result.end()) {
        fout << it1->first << " : " << "{";
        //it1->second是vector<int>类型,不能直接用fout输出
        for (const auto &it2 : it1->second) {
            fout << it2 << ",";
        }
        fout << "}" << endl;
        it1++;
    }

大功告成!

以上就是C++文件关键词快速定位出现的行号实现高效搜索的详细内容,更多关于C++搜索文件关键词的资料请关注脚本之家其它相关文章!

相关文章

  • C语言指针超详细讲解下篇

    C语言指针超详细讲解下篇

    指针提供了对地址操作的一种方法,因此,使用指针可使得 C 语言能够更高效地实现对计算机底层硬件的操作。另外,通过指针可以更便捷地操作数组。在一定意义上可以说,指针是 C 语言的精髓
    2022-04-04
  • C语言通讯录实例分享

    C语言通讯录实例分享

    这篇文章主要为大家分享了C语言通讯录实例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • C++11并发编程关于原子操作atomic的代码示例

    C++11并发编程关于原子操作atomic的代码示例

    今天小编就为大家分享一篇关于C++11并发编程关于原子操作atomic的代码示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C++实现中值滤波的示例代码

    C++实现中值滤波的示例代码

    本文主要介绍了C++实现中值滤波的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • C语言排序之 堆排序

    C语言排序之 堆排序

    这篇文章主要介绍了C语言排序之堆排序,文章基于C语言的相关资料展开详细内容,具有一定的参考资料,需要的小伙伴可以参考一下
    2022-04-04
  • C语言深入讲解语句与选择结构的使用

    C语言深入讲解语句与选择结构的使用

    这篇文章主要为大家介绍了C语言的语句与选择结构,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • C语言基础知识点指针的使用

    C语言基础知识点指针的使用

    这篇文章主要介绍了C语言基础知识点指针的使用,下面文章将让我们掌握指针的概念和用法、指针与数组之间的关系、指针指向的指针、如何使用指针变量做函数参数等更多相关内容,需要的小伙伴可以参考一下
    2022-03-03
  • C语言实现获取文件MD5值

    C语言实现获取文件MD5值

    MD5(Message Digest Algorithm 5)是一种常用的哈希函数算法,这篇文章主要介绍了C语言如何获取文件MD5值,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-08-08
  • 详解C++ sizeof(下)

    详解C++ sizeof(下)

    这篇文章主要介绍了C++ sizeof的相关资料,帮助大家更好的理解和学习c++,感兴趣的朋友可以了解下
    2020-08-08
  • C++ 冒泡排序数据结构、算法及改进算法

    C++ 冒泡排序数据结构、算法及改进算法

    冒泡排序是一种简单排序。这种排序是采用“冒泡策略”将最大元素移到最右边。在冒泡过程中,相邻两个元素比较,如果左边大于右边的,则进行交换两个元素。这样一次冒泡后,可确保最大的在最右边。然后执行n次冒泡后排序即可完毕
    2013-04-04

最新评论