1.前言
C++ primer 5e 中12.3章节示例了一个使用标准库的例子:文本查询程序,其中查询的字符串是作为word(单词)方式进行搜索的,其中使用了sstream库中的istringstream标准库来对一行内容进行单词分割判断。
这里改造了下,以以下场景进行示例练习使用标准库,
匹配方式:文本行只需包含 字符串就行,不用空白字符隔开的单词方式;
搜索方式:搜索指定字符串时,第一次搜索才进行实际的查找判断,并将结果集保存起来;如果后续查找,则直接从上一次保存的结果集合中给出结果;
2.测试文件
test.txt文件内容:
today is a good day
the girl is so beautiful
It was a beautiful morning.
aloha
hehe
how beautiful
beautiful view
3.运行结果
fs.good(): 1
fs.rdstate(): 0
getline parse start
read line 1:today is a good day
read line 2:the girl is so beautiful
read line 3:It was a beautiful morning.
read line 4:aloha
read line 5:hehe
read line 6:how beautiful
read line 7:beautiful view
getline parse end
enter word to look for,or q to quit :beautiful
[search] begin a new find action->
[search] end
beautiful occurs 4 times
(line 2 )the girl is so beautiful
(line 3 )It was a beautiful morning.
(line 6 )how beautiful
(line 7 )beautiful view
enter word to look for,or q to quit :beautiful
[find] you have do find action before,last find result:
beautiful occurs 4 times
(line 2 )the girl is so beautiful
(line 3 )It was a beautiful morning.
(line 6 )how beautiful
(line 7 )beautiful view
enter word to look for,or q to quit :hehe
[search] begin a new find action->
[search] end
hehe occurs 1 times
(line 5 )hehe
enter word to look for,or q to quit :he
[search] begin a new find action->
[search] end
he occurs 2 times
(line 2 )the girl is so beautiful
(line 5 )hehe
4.示例代码
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
using namespace std;
using line_no = vector<string>::size_type;
class QueryResult;
class TextQuery {
public:
TextQuery(ifstream& ifs);
QueryResult find(const string&) ;
private:
ifstream& fs;
shared_ptr<vector<string>> file;
map<string, shared_ptr<set<line_no>>>wm;
};
TextQuery::TextQuery(ifstream& ifs) :fs(ifs), file(new vector<string>)
{
string text;
//getline 需 #include <fstream>
int count = 0;
cout << " getline parse start" << endl;
while (getline (fs, text)) {
cout << " read line " << (++count) <<":"<< text<< endl;
file->push_back(text);
}
cout << " getline parse end" << endl;
}
class QueryResult {
friend ostream& print(ostream&, const QueryResult&);
public:
QueryResult(string s, shared_ptr<set<line_no>>p, shared_ptr<vector<string>>f)
:sought(s), lines(p), file(f){}
private:
string sought;
shared_ptr<set<line_no>>lines;
shared_ptr<vector<string>>file;
};
QueryResult TextQuery::find(const string & sought)
{
auto loc = wm.find(sought);
if (loc != wm.end())
{
cout << " [find] you have do find action before,last find result:" << endl;
return QueryResult(sought, loc->second, file);
}
string text;
//getline 需 #include <fstream>
cout << " [search] begin a new find action->" << endl;
shared_ptr<set<line_no>> lines;
lines.reset(new set<line_no>);
int linenum = 0;
for (string& text : *file)
{
if (text.find(sought) != string::npos)
{
//cout << "[find]find "<<sought<<" in line:"<<text << endl;
lines->insert(linenum);
}
linenum++;
}
/*
for (line_no num = 0 ;num <(*file).size();num++)
{
if ((*file)[num].find(sought) != string::npos)
{
//cout << "[find]find "<<sought<<" in line:"<<text << endl;
lines->insert(num);
}
}*/
cout << " [search] end" << endl;
wm.insert({ sought,lines });
return QueryResult(sought, lines, file);
}
ostream& print(ostream& os, const QueryResult &qr)
{
os << qr.sought << " occurs " << qr.lines->size() << " times" << endl;
for (auto num : *qr.lines)
os << "\t(line " << num + 1 << " )" << *(qr.file->begin() + num) << endl;
return os;
}
void runQueryies(ifstream & fs)
{
TextQuery tq(fs);
while (true) {
cout << "enter word to look for,or q to quit :";
string s;
if (!(cin >> s) || s == "q") break;
print(cout, tq.find(s)) << endl;
}
}
int main(int argc,char** argv)
{
string filename("K:\\temp\\test.txt");
//string filename(argv[0]);
ifstream fs(filename);
cout << "fs.good(): " << fs.good() << endl;
cout << "fs.rdstate(): " << fs.rdstate() << endl;
//cout << "fs.eof(): " << fs.eof() << endl;
//cout << "fs.fail(): " << fs.fail() << endl;
//cout << "fs.bad(): " << fs.bad() << endl;
/*enum _Iostate
{ // constants for stream states
_Statmask = 0x17};
static constexpr _Iostate goodbit = (_Iostate)0x0;
static constexpr _Iostate eofbit = (_Iostate)0x1;
static constexpr _Iostate failbit = (_Iostate)0x2;
static constexpr _Iostate badbit = (_Iostate)0x4;
*/
if (!fs.good())
{
cout << "open file fail,please check whether the file is exist:" << filename << endl;
return 0;
}
runQueryies(fs);
}
5.参考资料
《C++ primer》中文版 第5版,[美]stanley B.Lippman 等著,王刚 等译,电子工业出版社