C++文件關鍵詞快速定位出現(xiàn)的行號實現(xiàn)高效搜索
引言
博主剛開始學習c++,前段時間老師布置了c++的一個作業(yè):
給定兩個文件(一個源文件text4search.txt,一個文件keywords.txt包含需要在源文件中搜索的關鍵詞),要求輸出keywords.txt中每個關鍵詞在源文件中出現(xiàn)的行號。
舉個例子,如果keywords.txt中有一個關鍵詞是c++
,在text4search.txt中第1,7,9,43,543,586,2445行都出現(xiàn)了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; // 報錯函數(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; //每行單詞逐個檢查是不是在keywords里面出現(xiàn),而不是統(tǒng)計keyword在一行中出現(xiàn)的次數(shù) //這樣不用單獨寫一個函數(shù)統(tǒng)計一行中某個關鍵詞出現(xiàn)次數(shù),也能夠出現(xià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() { // 建立三個文件流對象并關聯(lián)相應文件,注意這里大家要修改為自己的文件路徑(或者使用命令行輸入) std::ifstream fin1; fin1.open("D:/University/Code/cpp_vscode/lab4/keywords.txt"); // 和keywords.txt建立關聯(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建立關聯(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建立關聯(lián) 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產(chǎn)生結果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>>
儲存每個關鍵詞到所出現(xiàn)行號的映射(由于關鍵詞出現(xiàn)的行號有多個,因此采用vector<int>
儲存行號組成的整數(shù)型向量)
具體代碼
首先,這里涉及到文件的輸入輸出,肯定是要用到<fstream>
的,然后自定義文件輸入輸出流對象并鏈接到對應的文件:
// 建立三個文件流對象并關聯(lián)相應文件,注意這里大家要修改為自己的文件路徑(或者使用命令行輸入) std::ifstream fin1; fin1.open("D:/University/Code/cpp_vscode/lab4/keywords.txt"); // 和keywords.txt建立關聯(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建立關聯(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建立關聯(lián) 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準備讀入每行中的單詞
接下來,我們的關鍵點在于,如何用比較好的方法搜索并儲存好每個關鍵詞出現(xiàn)的行號呢?
一般而言,有兩種搜索思路:
- 每次讀取一個keyword,在text全文中搜索這個keyword在哪些行出現(xiàn)了,記錄行號;
- 每次讀取text中的一行,再逐個讀取這一行中的每個詞,最后搜索這個詞是不是出現(xiàn)在keywords.txt中,如果出現(xiàn),則記錄該行的行號;
那么,哪一種搜索方法更好更高效呢?顯然是第二種。第一種方法思路簡單,但每次搜索全文的代價太高。以下是我采用第二種搜索的思路的代碼:
//sin讀入每行中的每個單詞 while (sin >> word) { //使用find函數(shù)和迭代器搜索每個sin讀入的單詞是否出現(xiàn)在keywords這個vector中 auto it = find(keywords.begin(), keywords.end(), word); if (it != keywords.end()) { //如果找到了,那么將這個關鍵詞對應的行號存入map中 resultMap[word].push_back(lineNum); }
走到這里,已經(jīng)基本成功啦!最后只需要把我們的答案正確輸出,這里我使用迭代器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++文件關鍵詞快速定位出現(xiàn)的行號實現(xiàn)高效搜索的詳細內容,更多關于C++搜索文件關鍵詞的資料請關注腳本之家其它相關文章!
相關文章
C++20 特性 協(xié)程 Coroutines(1)
這篇文章主要給大家分享得是C++20 得特性 協(xié)程 Coroutines,下面文章內容我們將來具體介紹什么是協(xié)程,協(xié)程得好處等知識點,需要的朋友可以參考一下2021-10-10遞歸法求最大公約數(shù)和最小公倍數(shù)的實現(xiàn)代碼
今天整理了一下用遞歸法求最大公約數(shù)(gcd)和最小公倍數(shù)(lcm)。主要的工作是求最大公約數(shù)。數(shù)學上可以用輾轉法求最大公約數(shù)2013-05-05