C++文件關(guān)鍵詞快速定位出現(xiàn)的行號實(shí)現(xiàn)高效搜索
引言
博主剛開始學(xué)習(xí)c++,前段時(shí)間老師布置了c++的一個(gè)作業(yè):
給定兩個(gè)文件(一個(gè)源文件text4search.txt,一個(gè)文件keywords.txt包含需要在源文件中搜索的關(guān)鍵詞),要求輸出keywords.txt中每個(gè)關(guān)鍵詞在源文件中出現(xiàn)的行號。

舉個(gè)例子,如果keywords.txt中有一個(gè)關(guān)鍵詞是c++,在text4search.txt中第1,7,9,43,543,586,2445行都出現(xiàn)了c++,那么應(yīng)該輸出c++:{1 7 9 43 543 586 2445 }。
完整版代碼
(代碼已在vscode c++11標(biāo)準(zhǔn)運(yùn)行成功)
#include <algorithm>
#include <fstream>
#include <iostream>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
// 報(bào)錯(cuò)函數(shù)
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;
//每行單詞逐個(gè)檢查是不是在keywords里面出現(xiàn),而不是統(tǒng)計(jì)keyword在一行中出現(xiàn)的次數(shù)
//這樣不用單獨(dú)寫一個(gè)函數(shù)統(tǒng)計(jì)一行中某個(gè)關(guān)鍵詞出現(xiàn)次數(shù),也能夠出現(xiàn)一次關(guān)鍵詞就壓入行號一次
while (sin >> word) {
auto it = find(keywords.begin(), keywords.end(), word);
if (it != keywords.end()) {
resultMap[word].push_back(lineNum);
}
}
}
return resultMap;
}
int main() {
// 建立三個(gè)文件流對象并關(guān)聯(lián)相應(yīng)文件,注意這里大家要修改為自己的文件路徑(或者使用命令行輸入)
std::ifstream fin1;
fin1.open("D:/University/Code/cpp_vscode/lab4/keywords.txt"); // 和keywords.txt建立關(guān)聯(lián)
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建立關(guān)聯(lián)
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建立關(guān)聯(lián)
if (!fout) {
error("cannot open output file", "D:/University/Code/cpp_vscode/lab4/result.txt");
}
// 將keywords存入keys這個(gè)字符串向量中(用fin1)
vector<string> keys;
string s;
while (fin1 >> s) {
keys.push_back(s);
}
fin1.close();
// 利用fin2和keys產(chǎn)生結(jié)果map
map<string, vector<int>> result = keyCount(fin2, keys);
fin2.close();
//輸出,由于map會(huì)自動(dòng)按照字典序排序,而行號也是按照升序逐行檢測,因此輸出不用再排序
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;
}下面結(jié)合代碼講一講我的思路。
這道題的難點(diǎn)在于如何選取正確、高效的存儲(chǔ)方法和搜索方法:
顯然我們不能簡單的挨個(gè)讀取text中的單詞,找到一個(gè)關(guān)鍵詞就輸出一個(gè)行號——這樣輸出的行號是混亂的。
基本思路
- 采用
vector<string>儲(chǔ)存所有keywords; - 采用
map<string,vector<int>>儲(chǔ)存每個(gè)關(guān)鍵詞到所出現(xiàn)行號的映射(由于關(guān)鍵詞出現(xiàn)的行號有多個(gè),因此采用vector<int>儲(chǔ)存行號組成的整數(shù)型向量)
具體代碼
首先,這里涉及到文件的輸入輸出,肯定是要用到<fstream>的,然后自定義文件輸入輸出流對象并鏈接到對應(yīng)的文件:
// 建立三個(gè)文件流對象并關(guān)聯(lián)相應(yīng)文件,注意這里大家要修改為自己的文件路徑(或者使用命令行輸入)
std::ifstream fin1;
fin1.open("D:/University/Code/cpp_vscode/lab4/keywords.txt"); // 和keywords.txt建立關(guān)聯(lián)
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建立關(guān)聯(lián)
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建立關(guān)聯(lián)
if (!fout) {
error("cannot open output file", "D:/University/Code/cpp_vscode/lab4/result.txt");
}用文件輸入流對象fin每次讀入text中的一行,再用字符串輸入流對象sin逐個(gè)讀入該行的單詞:
int lineNum = 0;
//讀入文件的每一行
while (getline(inputFile, line)) {
++lineNum;
std::istringstream sin(line);//新建sin準(zhǔn)備讀入每行中的單詞接下來,我們的關(guān)鍵點(diǎn)在于,如何用比較好的方法搜索并儲(chǔ)存好每個(gè)關(guān)鍵詞出現(xiàn)的行號呢?
一般而言,有兩種搜索思路:
- 每次讀取一個(gè)keyword,在text全文中搜索這個(gè)keyword在哪些行出現(xiàn)了,記錄行號;
- 每次讀取text中的一行,再逐個(gè)讀取這一行中的每個(gè)詞,最后搜索這個(gè)詞是不是出現(xiàn)在keywords.txt中,如果出現(xiàn),則記錄該行的行號;
那么,哪一種搜索方法更好更高效呢?顯然是第二種。第一種方法思路簡單,但每次搜索全文的代價(jià)太高。以下是我采用第二種搜索的思路的代碼:
//sin讀入每行中的每個(gè)單詞
while (sin >> word) {
//使用find函數(shù)和迭代器搜索每個(gè)sin讀入的單詞是否出現(xiàn)在keywords這個(gè)vector中
auto it = find(keywords.begin(), keywords.end(), word);
if (it != keywords.end()) {
//如果找到了,那么將這個(gè)關(guān)鍵詞對應(yīng)的行號存入map中
resultMap[word].push_back(lineNum);
}走到這里,已經(jīng)基本成功啦!最后只需要把我們的答案正確輸出,這里我使用迭代器it1輸出map中的關(guān)鍵詞,由于map中的value值實(shí)際是vector類型,不能簡單使用it1->second輸出,因此我們再定義一個(gè)it2輸出vector<int>中的內(nèi)容
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++文件關(guān)鍵詞快速定位出現(xiàn)的行號實(shí)現(xiàn)高效搜索的詳細(xì)內(nèi)容,更多關(guān)于C++搜索文件關(guān)鍵詞的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
VS2019簡單快速的打包可安裝項(xiàng)目(圖文教程)
這篇文章主要介紹了VS2019簡單快速的打包可安裝項(xiàng)目,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
從匯編看c++中默認(rèn)構(gòu)造函數(shù)的使用分析
c++中,如果為一個(gè)類沒有明確定義一個(gè)構(gòu)造函數(shù),那么,編譯器就會(huì)自動(dòng)合成一個(gè)默認(rèn)的構(gòu)造函數(shù)。下面,通過匯編程序,來看一下其真實(shí)情況2013-05-05
C語言實(shí)現(xiàn)“幸運(yùn)數(shù)”的實(shí)例詳解
這篇文章主要介紹了C語言實(shí)現(xiàn)“幸運(yùn)數(shù)”的實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-07-07
C++實(shí)現(xiàn)三子棋游戲詳細(xì)介紹(附代碼)
大家好,本篇文章主要講的是C++實(shí)現(xiàn)三子棋游戲詳細(xì)介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下2022-01-01
C++20 特性 協(xié)程 Coroutines(1)
這篇文章主要給大家分享得是C++20 得特性 協(xié)程 Coroutines,下面文章內(nèi)容我們將來具體介紹什么是協(xié)程,協(xié)程得好處等知識點(diǎn),需要的朋友可以參考一下2021-10-10
遞歸法求最大公約數(shù)和最小公倍數(shù)的實(shí)現(xiàn)代碼
今天整理了一下用遞歸法求最大公約數(shù)(gcd)和最小公倍數(shù)(lcm)。主要的工作是求最大公約數(shù)。數(shù)學(xué)上可以用輾轉(zhuǎn)法求最大公約數(shù)2013-05-05

