文字查詢程式c++primer12.32

TinnCHEN發表於2019-04-11

標頭檔案StrBlob以及StrBlobPtr

//根據題目要求用自己定義的StrBlob來代替vector<string>來儲存輸入檔案
//可以更加安全的共享底層資料
#include<iostream>
#include<vector>
#include<string>
#include<memory>
#include<fstream>

using namespace std;

class StrBlob {  //自定義管理動態vector<string>的類,可以讓其物件共享同一個data
	friend class StrBlobPtr;
public:
	typedef vector<string>::size_type size_type;
	StrBlob() : data(make_shared<vector<string>>()) {}
	StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}
	~StrBlob() { cout << " ~ Blob success " << endl; }
	size_type size() const { return data->size(); }
	bool empty()const { return data->empty(); }
	void push_back(const string &st) const { data->push_back(st); }
	void pop_back() const;
	string &front() const;
	string &back() const;
	StrBlobPtr begin();
	StrBlobPtr end();
private:
	shared_ptr<vector<string>> data;
	void check(size_type t, const string &msg) const;
};

//檢查一個給定的索引值是否在合法範圍內
void StrBlob::check(size_type t, const string &msg) const { 
	if (t >= data->size())
		throw out_of_range(msg);
}

void StrBlob::pop_back() const {
	check(0, "pop back on empty StrBlob");
	data->pop_back();
}

string & StrBlob::front() const {
	check(0, "pop back on empty StrBlob");
	return data->front();
}

string & StrBlob::back() const {
	check(0, "pop back on empty StrBlob");
	return data->back();
}


class StrBlobPtr { //為StrBlob提供保護,指向Blob的data防止我們訪問其可能產生的空懸指標
public:
//預設情況下StrBlobPtr指向data的第一個下標
	StrBlobPtr() :curr(0) { }
	StrBlobPtr(StrBlob &a, size_t sz = 0) :wptr(a.data), curr(sz) { }
	~StrBlobPtr(){ cout << " ~ BlobPtr success " << endl; }
	string &deref() const; //用來解引用
	StrBlobPtr& incr();//用來遞增
	bool operator != (const StrBlobPtr &x) { return this->curr != x.curr; }
private:
	size_t curr;
	//check要檢查指標指向的vector是否還存在
	shared_ptr<vector<string>> check(size_t, const string&) const;
	weak_ptr<vector<string>> wptr;
};

shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg) const {
	auto ret = wptr.lock();
	if (!ret) {
		throw runtime_error("unbound StrBlobPtr");
	}
	if (i >= ret->size()) {
		throw out_of_range(msg);
	}
	return ret;
}

string & StrBlobPtr::deref() const {
	auto p = check(curr, "dereference past end");
	return (*p)[curr];
}

StrBlobPtr& StrBlobPtr::incr() {
	auto p = check(curr, "increment past end of StrBlobPtr");
	++curr;
	return *this;
}


StrBlobPtr StrBlob::begin() {
	return StrBlobPtr(*this);
}
StrBlobPtr StrBlob::end() {
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}

標頭檔案TextQuery以及QueryResult

#include<iostream>
#include<vector>
#include<new>
#include<set>
#include<map>
#include<fstream>
#include<algorithm>
#include<memory>
#include<sstream>
#include<string>
#include<iterator>
#include<iterator>
#include"Blob.h"
using namespace std;

class QueryResult;
class TextQuery { //儲存輸入檔案
public:
	using LineNo = vector<string>::size_type;
	TextQuery();
	TextQuery(ifstream &infile);
	~TextQuery(){ cout << " ~ TextQuery success " << endl; }
	QueryResult query(const string &s) const;//返回一個查詢結果
private:
	map<string, shared_ptr<set<LineNo>>> result; //通過字串來查詢對應的行號
	//shared_ptr<vector<string>> data;  
	StrBlob data;//按行儲存輸入的檔案
};

class QueryResult { //儲存查詢結果
	friend ostream& print(ostream &os, QueryResult &qr);
public:
	QueryResult(const string &s, StrBlob vec, shared_ptr<set<TextQuery::LineNo>> n) :
	           word(s),data(vec),nos(n){ 
	}
	~QueryResult(){ cout << " ~ QueryResult success " << endl; }
	//以下三個是根據12.33題目要求擴充套件,暫時未用到
	set<TextQuery::LineNo>::iterator begin() const { return nos->begin(); }
	set<TextQuery::LineNo>::iterator end() const { return nos->end(); }
	StrBlob get_file() const { return data; }
private:
	string word;
	//shared_ptr<vector<string>> data;
	StrBlob data; //與TextQuery共享data資料
	shared_ptr<set<TextQuery::LineNo>> nos;//儲存與給定單詞關聯的行號
};

TextQuery::TextQuery(ifstream &infile) : data(){
	LineNo lineNo = 0;
	for (string line; getline(infile, line); ++lineNo) {
		data.push_back(line);
		istringstream line_stream(line);
		for (string lineword; line_stream >> lineword; ) {
			auto &nos = result[lineword];
			if (!nos) //當行號第一次出現時此指標為空
				nos.reset(new set<LineNo>);//分配一個新的set
			nos->insert(lineNo);
			}
	}
	/*string text;
	while (getline(infile, text)) {
		data->push_back(text);
		int n = data->size() - 1;
		istringstream line(text);
		string word;
		while (line >> word) {
			auto &lines = result[word];
			if (!lines)
				lines.reset(new set<LineNo>);
			lines->insert(n);
		}
	}*/
}


QueryResult TextQuery::query(const string& s) const {
	shared_ptr<set<TextQuery::LineNo>> nodata(make_shared<set<LineNo>>());
	auto found = result.find(s);
	if (found != result.end())
		return QueryResult(s, data, found->second);
	else
		return QueryResult(s, data, nodata);
}

ostream& print(ostream &out, QueryResult &qr) {
	out << qr.word << " occurs " << qr.nos->size() << (qr.nos->size() > 1 ? "time" : "times") << endl;
	for (auto i : *qr.nos) {
	    StrBlobPtr p(qr.data, i);
		out << "( line " << i + 1 << ")" << p.deref() << endl;
	}
	return out;
}

主函式

#include<iostream>
#include<vector>
#include<new>
#include<set>
#include<algorithm>
#include<memory>
#include<sstream>
#include<string>
#include"ClassTQ.h"
using namespace std;

void runQueries(ifstream &infile) {
	TextQuery tq(infile);
	string s;
	while (cin >> s && s != "q") {
	    cout << "請輸入要查詢的字串或者輸入q來退出查詢:" << endl;
		print(cout, tq.query(s));
	}
}

int main() {
	ifstream txt1;
	txt1.open("1.txt", ios::in);
	cout << "open 1.txt success" << endl;
	runQueries(txt1);
	txt1.close();
	return 0;
}

相關文章