C++ Primer 第十二章 12.3 使用标准库:文本查询程序 练习

练习

12.27

这个程序已经可以完成论文所作的功能了


class QueryResult {
	//懒得重复写,所以使用类型别名
	using str_vec_ptr = std::shared_ptr<vector<string>>;
	using str_set_map_ptr = std::shared_ptr<map<string, set<size_t>>>;
	using str_map_ptr = std::shared_ptr<map<string, size_t>>;
	friend ostream& print(ostream& out, const QueryResult& result);
public:
	QueryResult(string word,str_vec_ptr p1,str_set_map_ptr p2,str_map_ptr p3):query_word(word),text_content(p1),word_to_line_set_map(p2),word_count_map(p3) {

	}
private:
	//不使用类内初始化,使用TextQuery传入的参数进行初始化
	str_vec_ptr text_content;
	str_set_map_ptr word_to_line_set_map;
	str_map_ptr word_count_map;
	string query_word;
};

class TextQuery {
public:
	//默认有50行
	TextQuery(ifstream& ifile) {
		string word;
		while (std::getline(ifile, word)) {
			text_content->push_back(word);
		}
	};
	QueryResult query(const string&);
private:
	//因为需要共享数据,所以这些数据成员全部写成智能指针的形式
	//懒得在初始化列表中初始化参数了,直接使用类内初始化
	std::shared_ptr<vector<string>> text_content = std::make_shared<vector<string>>();
	std::shared_ptr<map<string, set<size_t>>> word_to_line_set_map = std::make_shared<map<string, set<size_t>>>();
	std::shared_ptr<map<string, size_t>> word_count_map = std::make_shared<map<string, size_t>>();
	
};

QueryResult TextQuery::query(const string& str) {

if ((*word_count_map).find(str)!= (*word_count_map).end()) {
		return QueryResult(str, text_content, word_to_line_set_map, word_count_map);
	}
	size_t line = 1;
	size_t word_count = 0;
	set<size_t> word_appear_line_set;
	for (const auto& line_str : *text_content) {
		string single_word;
		std::istringstream single_text_stream(line_str);
		while (single_text_stream >> single_word) {
			if (str == single_word) {
				word_appear_line_set.insert(line);
				//统计次数的加一
				++word_count;
				
			}
		}
		++line;
	}
	(*word_to_line_set_map)[str] = word_appear_line_set;
	(*word_count_map)[str] = word_count;
	return QueryResult(str,text_content,word_to_line_set_map,word_count_map);
}

ostream& print(ostream& out,const QueryResult& result) {
	string target_word = result.query_word;
	out << target_word << " appear " << (*result.word_count_map)[target_word] << " times" << endl;
	for (const auto & line : (*result.word_to_line_set_map)[target_word] ) {
		out << "line:" << line << " " << (*result.text_content)[line - 1]<<endl;
	}
	return out;
}

void runQueries(ifstream &infile) {
	TextQuery tq(infile);
	while (true) {
		cout << "输入你要查询的词" << endl;
		string s;
		if ((!(cin>>s)||s=="q")) {
			break;
		}
		print(cout,tq.query(s))<<endl;
	}
}

12.28

这里其实就是将上面的拆分的内容写到一个文件里面,这里就不写了

12.29

习惯使用while,如果在所有可以使用while或者do_while的地方都使用while,我就不用考虑用while还是do_while了,而且while可以完成do_while的工作,所以我倾向于使用while。

12.30

代码已经写在了12.27 和书上的区别在于,书中是在从文件中获取文本时,就已经构建好了索引。

我是在查询的时候构建索引,如果再次查询,索引已经存在则直接返回结果,如果不存在则构建索引

12.31

在我的程序中,使用vector代替set更加的麻烦,因为set本身就不允许重复的关键字存在,而vector则需要自己判断

12.32

将QueryResult和TextQuery类中的std::shared_ptr<vector>改成StrBlob就可以了,因为StrBolb内部就维护了一个std::shared_ptr<vector>,我们可以直接写StrBlob。

12.33

我目前不清楚
添加名为begin和end的成员,返回一个迭代器,指向给定查询返回的行号的set中的位置,这句话是什么意思?

如果是返回给定查询的包含所有行号的set的begin和end,那么可以写成

set<size_t>::iterator begin() {
		return (*word_to_line_set_map)[query_word].begin();
	};
	set<size_t>::iterator end() {
		return (*word_to_line_set_map)[query_word].end();
	};

而get_file()返回一个shared_ptr,指向QueryResult对象中的文件。这句话,指的如果是包含所有的文本的vector<string>的话,那么可以写成下面的形式

str_vec_ptr get_file() {
		return text_content;
	}
发布了54 篇原创文章 · 获赞 6 · 访问量 3305

猜你喜欢

转载自blog.csdn.net/zengqi12138/article/details/104417613