练习12.30:
#include <iostream>
#include <string>
using namespace std;
#include <vector>
#include <fstream>
#include <memory>
#include <set>
#include <map>
#include <sstream>
class QueryResult;
class TextQuery
{
public:
using line_no = std::vector<std::string>::size_type;
//构造函数
TextQuery(std::ifstream&);
QueryResult query(const std::string&)const;
private:
std::shared_ptr<std::vector<std::string>>file;
std::map<std::string, std::shared_ptr<set<line_no>>>wm;
};
TextQuery::TextQuery(ifstream& is) :file(new vector<string>)
{
string text;
while (getline(is, text))
{
file->push_back(text);
size_t n = file->size() - 1;
istringstream line(text);
string word;
while (line >> word)
{
//如果单词不在wm中,以之为下标在wm中添加一项
auto& lines = wm[word];
if (!lines)
{
//此时lines是新插入map中的一项,string部分为word,现在创建set
lines.reset(new set<line_no>);
}
//将行号插入set中
lines->insert(n);
}
}
}
class QueryResult
{
friend ostream& print(ostream& os, const QueryResult& qr);
public:
using line_no = std::vector<std::string>::size_type;
//构造函数
QueryResult(std::string s, std::shared_ptr<std::set<line_no>>p, std::shared_ptr<std::vector<std::string>>f) :
sought(s), lines(p), file(f) { }
private:
//查询单词
std::string sought;
//出现的行号
std::shared_ptr<std::set<line_no>> lines;
//输入文件
std::shared_ptr<std::vector<std::string>> file;
};
//query函数实现
QueryResult TextQuery::query(const string& sought)const
{
//如果未找到sought,我们返回一个指向此set的指针
static shared_ptr<set<line_no>>nodata(new set<line_no>);
//使用find而不是下标运算符来查找单词,避免将单词添加到wm中!
auto loc = wm.find(sought);
if (loc == wm.end())
{
//未找到
return QueryResult(sought, nodata, file);
}
else
{
return QueryResult(sought, loc->second, file);
}
}
string make_plural(size_t ctr, const string& word, const string& ending)
{
return (ctr > 1) ? word + ending : word;
}
//打印结果
ostream& print(ostream& os, const QueryResult& qr)
{
//如果找到了单词,打印出现的次数和所有出现的位置
os << qr.sought << "occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "time", "s") << endl;
//打印单词出现的每一行
for (auto num : *qr.lines)
{
//避免行号从0开始给用户造成困惑
os << "\t(line" << num + 1 << ")" << *(qr.file->begin() + num) << endl;
}
return os;
}
void runQueries(ifstream& infile)
{
TextQuery tq(infile);
while (true)
{
cout << "enter word to look for,or q to quit: ";
string s;
if (!(cin >> s) || s == "q")
{
break;
}
print(cout, tq.query(s)) << endl;
}
}
int main()
{
ifstream infile("text.txt");
runQueries(infile);
system("pause");
return 0;
}
结果:
文件内容:
练习12.31:
使用vector代替set就需要将vector容器元素重新排序才能从小到大打印行,且vector中可能会出现多个一样的行,影响结果
使用set更好
练习12.32:
#include <iostream>
#include <string>
using namespace std;
#include <vector>
#include <fstream>
#include <memory>
#include <set>
#include <map>
#include <sstream>
class TextQuery;
class StrBlobPtr;
class StrBlob {
friend class StrBlobPtr;
friend class TextQuery;
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<std::string>il);
size_type size()const { return data->size(); }
bool empty()const { return data->empty(); }
void push_back(const std::string& t) { data->push_back(t); }
void pop_back();
StrBlobPtr begin(); //{ return StrBlobPtr(*this); }
StrBlobPtr end();
std::string& front()const;
std::string& back()const;
private:
std::shared_ptr<std::vector<std::string>>data;
void check(size_type i, const std::string& msg)const;
};
StrBlob::StrBlob() :data(make_shared<vector<string>>()) { }
StrBlob::StrBlob(initializer_list<string>il) :data(make_shared<vector<string>>(il)) { }
void StrBlob::check(size_type i, const string& msg)const
{
if (i >= data->size())
{
throw out_of_range(msg);
}
}
string& StrBlob::front()const
{
check(0, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back()const
{
check(0, "back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
//StrBlob的指针类
class StrBlobPtr
{
friend bool noEqual(const StrBlobPtr& ls, const StrBlobPtr& rs);
public:
StrBlobPtr() : curr(0) { }
StrBlobPtr(StrBlob& a, size_t sz = 0) :wptr(a.data), curr(sz) { }
std::string& deref() const;
StrBlobPtr& incr();
private:
std::shared_ptr<std::vector<std::string>>check(std::size_t, const std::string&)const;
std::weak_ptr<std::vector<std::string>>wptr;
std::size_t curr;
};
std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(std::size_t i, const std::string& msg)const
{
auto ret = wptr.lock();
if (!ret)
{
throw std::runtime_error("unbound StrBlobPtr");
}
if (i >= ret->size())
{
throw out_of_range(msg);
}
return ret;
}
std::string& StrBlobPtr::deref()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& StrBlobPtr::incr()
{
//递增curr,判断curr位于合理位置,不合理位置不递增
check(curr, "incrasement past end of StrBlobPtr");
++curr;
return *this;
}
StrBlobPtr StrBlob::begin()
{
return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end()
{
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
//重载不等于号
bool noEqual(const StrBlobPtr& ls, const StrBlobPtr& rs)
{
auto l = ls.wptr.lock();
auto r = rs.wptr.lock();
if (l == r && ls.curr == rs.curr)
{
return false;
}
else
{
return true;
}
}
class QueryResult;
class TextQuery
{
public:
using line_no = std::vector<std::string>::size_type;
//构造函数
TextQuery(std::ifstream&);
QueryResult query(const std::string&)const;
private:
StrBlob strb;
std::map<std::string, std::shared_ptr<set<line_no>>>wm;
};
TextQuery::TextQuery(ifstream& is):strb()
{
string text;
while (getline(is, text))
{
strb.push_back(text);
//file->push_back(text);
size_t n = strb.size() - 1;
//size_t n = file->size() - 1;
istringstream line(text);
string word;
while (line >> word)
{
//如果单词不在wm中,以之为下标在wm中添加一项
auto& lines = wm[word];
if (!lines)
{
//此时lines是新插入map中的一项,string部分为word,现在创建set
lines.reset(new set<line_no>);
}
//将行号插入set中
lines->insert(n);
}
}
}
class QueryResult
{
friend ostream& print(ostream& os, const QueryResult& qr);
public:
using line_no = std::vector<std::string>::size_type;
//构造函数
QueryResult(std::string s, std::shared_ptr<std::set<line_no>>p, StrBlob& strb) :
sought(s), lines(p),strb(strb) { }
private:
//查询单词
std::string sought;
//出现的行号
std::shared_ptr<std::set<line_no>> lines;
//输入文件
StrBlob strb;
//std::shared_ptr<std::vector<std::string>> file;
};
//query函数实现
QueryResult TextQuery::query(const string& sought)const
{
StrBlob st = strb;
//如果未找到sought,我们返回一个指向此set的指针
static shared_ptr<set<line_no>>nodata(new set<line_no>);
//使用find而不是下标运算符来查找单词,避免将单词添加到wm中!
auto loc = wm.find(sought);
if (loc == wm.end())
{
//未找到
return QueryResult(sought, nodata,st);
}
else
{
return QueryResult(sought, loc->second, st);
}
}
string make_plural(size_t ctr, const string& word, const string& ending)
{
return (ctr > 1) ? word + ending : word;
}
//打印结果
ostream& print(ostream& os, const QueryResult& qr)
{
//如果找到了单词,打印出现的次数和所有出现的位置
os << qr.sought << "occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "time", "s") << endl;
//打印单词出现的每一行
for (auto num : *qr.lines)
{
//避免行号从0开始给用户造成困惑
os << "\t(line" << num + 1 << ")" << *(qr.strb.front().begin() + num) << endl;
}
return os;
}
void runQueries(ifstream& infile)
{
TextQuery tq(infile);
while (true)
{
cout << "enter word to look for,or q to quit: ";
string s;
if (!(cin >> s) || s == "q")
{
break;
}
print(cout, tq.query(s)) << endl;
}
}
int main()
{
ifstream infile("text.txt");
runQueries(infile);
system("pause");
return 0;
}
结果:
练习12.33:
class QueryResult
{
friend ostream& print(ostream& os, const QueryResult& qr);
public:
using line_no = std::vector<std::string>::size_type;
//构造函数
QueryResult(std::string s, std::shared_ptr<std::set<line_no>>p, std::shared_ptr<std::vector<std::string>>f) :
sought(s), lines(p), file(f) { }
std::vector<string>::iterator& begin();
std::vector<string>::iterator& end();
std::shared_ptr<QueryResult>& get_file();
private:
//查询单词
std::string sought;
//出现的行号
std::shared_ptr<std::set<line_no>> lines;
//输入文件
std::shared_ptr<std::vector<std::string>> file;
};