題目:在給定文件中查詢單詞。查詢結果是單詞在文件中出現的次數及所在行的列表。如果一個單詞在一行中多次出現,此行只顯示一次,行會按照升序輸出。
效果如下:
在此程序的實現中使用到的標準庫內容包括:
(1)ifstream:用來綁定並打開指定的文本。
(2)vector<string>:用來保存整個文本,每行保存爲vector中的元素。
(3)istringstream:用來將每行分解爲單詞。
(4)multiset:用來保存每個單詞出現的行號,保證了行號按升序排列;一個單詞在某行中出現多次,行號會重複保存;
(5)set:用來將multiset中的重複去除,用於一個單詞在某行中出現多次,只顯示一次;
(6)map:將單詞和它出現的行號的multiset關聯起來。
(7)shared_ptr:用於在類之間進行數據共享;
設計思想:
1.當我們設計一個類時,在真正實現成員之前先編寫程序使用這個類,是一種非常有用的方法。通過這種方法,可以看到類是否具有我們所需要的操作。
2.在類的設計過程中,最重要的就是接口的設計,也就是頭文件的設計。
注意的問題:
1.IO對象無拷貝或賦值,需要以引用的方式傳遞參數和返回流。
2.auto& lines = wm[word];這裏也需要是按引用傳遞,否則會發生拷貝,不能操作map中的set,結果爲空。
源代碼與C++Primer(第5版)第十二章給出的稍有改動,我認爲書中講的統計單詞出現次數的方法不合理。
1.main.cpp
#include "TxtQuery.h"
#include "queryResult.h"
#include "iostream"
void runQueries(std::ifstream& infile)
{
TxtQuery wordQuery(infile);
while (true)
{
std::cout<< "enter word to look for, or q to quit:";
std::string word;
if (!(std::cin >> word) || word == "q") break;
print(std::cout, wordQuery.query(word));
}
}
int main()
{
std::ifstream infile("1.txt");
runQueries(infile);
}
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <map>
#include <set>
#include <fstream>
#include "queryResult.h"
class TxtQuery
{
public:
TxtQuery();
~TxtQuery();
TxtQuery(std::ifstream& in);
queryResult query(const std::string& word);
private:
std::shared_ptr<std::vector<std::string>> file;
std::map<std::string, std::shared_ptr<std::multiset<int>>> wm;
};
#include "TxtQuery.h"
#include <sstream>
TxtQuery::TxtQuery()
{
}
TxtQuery::~TxtQuery()
{
}
TxtQuery::TxtQuery(std::ifstream& in) :file(new std::vector<std::string>)
{
std::string text;
while (std::getline(in, text))
{
file->push_back(text);
int n = file->size();
std::istringstream line(text);
std::string word;
while (line >> word)
{
auto& lines = wm[word];
if (!lines)
{
lines.reset(new std::multiset<int>);
}
lines->insert(n);
}
}
}
queryResult TxtQuery::query(const std::string& word)
{
static std::shared_ptr<std::multiset<int>> nodata(new std::multiset<int>);
auto loc = wm.find(word);
if(loc == wm.end())
{
return queryResult(word, nodata, file);
}
else
{
return queryResult(word, loc->second, file);
}
}
4、queryResult.h
#pragma once
#include <string>
#include <memory>
#include <set>
#include <vector>
class queryResult
{
public:
queryResult();
~queryResult();
queryResult(const std::string sought, std::shared_ptr<std::multiset<int>> lines, std::shared_ptr<std::vector<std::string>> file) :
sought(sought)
,lines(lines)
,file(file) {}
friend std::ostream& print(std::ostream&, const queryResult&);
private:
std::string sought;
std::shared_ptr<std::multiset<int>> lines;
std::shared_ptr<std::vector<std::string>> file;
};
#include "queryResult.h"
#include <iostream>
queryResult::queryResult()
{
}
queryResult::~queryResult()
{
}
std::ostream& print(std::ostream& os, const queryResult& qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " " << "times" << std::endl;
//用multiset初始化set,重複的內容自動去除
std::set<int> single(std::begin(*qr.lines), end(*qr.lines));
for (auto num : single) {
os << "\t(line " << num << ")" << *(qr.file->begin() + num - 1) << std::endl;
}
std::cout << std::endl;
return os;
}