C++ Primer : 第十二章 : 文本查询程序

C++ Primer书上这个例子讲的很不错,写写帮助自己理解标准库和智能指针。


.h 文件内容

#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <sstream>
#include <memory>

class QueryResult;

class TextQuery {

public:

	using line_no = std::vector<std::string>::size_type;

	TextQuery(std::ifstream& ifs);

	// 返回string的信息
	QueryResult query(const std::string&) const;

private:

	std::shared_ptr<std::vector<std::string>> words_file;
	std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;

};


class QueryResult {

	friend std::ostream& print(std::ostream&, const QueryResult&);
public:
	
	QueryResult(std::string s, std::shared_ptr<std::vector<std::string>> wf, std::shared_ptr<std::set<size_t>> l) : sought(s), file(wf), lines(l){}


private:
	std::string sought; // 要查询的单词
	std::shared_ptr<std::vector<std::string>> file; // 输入文件
	std::shared_ptr<std::set<size_t>> lines; // 保存出现的行号

};

.cpp 文件内容

#include "TextQuery.h"


TextQuery::TextQuery(std::ifstream& ifs) : words_file(new std::vector<std::string>)
{
	std::string text;
	while (getline(ifs, text)){

		words_file->push_back(text);
		// 记录当前行号
		size_t n = words_file->size() - 1;

		// 获取每行每个单词
		std::istringstream line(text);
		std::string word;
		while (line >> word){

			auto &ckeck = wm[word];
			if (nullptr == ckeck)
				ckeck.reset(new std::set<line_no>);

			ckeck->insert(n);

		}
	}

}

QueryResult TextQuery::query(const std::string& s) const {

	// 保存一个静态对象  如果未能找到单词,返回此对象
	static std::shared_ptr<std::set<size_t>> nodata(new std::set<size_t>);

	auto location = wm.find(s);

	if (location == wm.end())
		return QueryResult(s, words_file, nodata);
	else
		return QueryResult(s, words_file, location->second);
}

std::ostream& print(std::ostream& os, const QueryResult& qr){

	os << qr.sought << " occurs " << qr.lines->size() << " "
	   << (qr.lines->size() > 1 ? "times" : "time")   << std::endl;

	for (auto num : *qr.lines)
		os << "	(line " << num + 1 << ")"
		   << *(qr.file->begin() + num)  << std::endl;
	return os;
}


将TextQuery的word_file成员和wm的值set都放在智能指针内,以便QueryResult类可以在正常访问。


TextQuery类:

TextqUuery的构造函数接受一个ifstream,用来读取文件,构造函数的初始化列表中,并且将word_file初始化为一个空的vector, getline从文件中读取一行存入string text中,首先将这一行的内容储存在word_file中,然后计算该行的行号,即就是word_file的大小size() - 1,istringstream对象用来读取string text中的每个单词,如果单词不在wm中,将这个单词对应的set申请一个新的内存空间, 然后将这个单词存入wm的string中,并将它所在的行号存入wm的set中,如果这个单词存在wm中,即使这个单词是第二次或第二次之后出现在同一行,lines->insert(n)并不会执行,因为set不允许重复关键字出现。


QueryResult类中,print函数将查找到的结果输出到屏幕。

QueryResult的构造函数接受一个string,一个shared_ptr,类型为set<size_t>, 还有一个shared_ptr,类型为vector<string>,参数string表示要查询的单词,sett的shared_ptr指向TextQuery的wm中的set,vector的shared_ptr指向TextQuery中的word_file。



TextQuerty中的query函数接受一个string,表示要查询的单词,在函数里声明了一个静态智能指针类型,用来表示未找到单词的set,表示没有该单词的行数可显示,然后在wm中查找该单词。


print函数用于打印给定的QueryResult对象:如果找到了单词,先打印这个单词和出现的次数,qr.lines->size();表示这个set的大小,即就是表示这个单词出现的次数;

然后在for循环中,num依次获取到这个单词出现的行数,由于我们习惯从1开始计数,因此将num + 1;然后在file中找到这一行的数据,*(qr.file->begin() + num), 从file这个vector的首元素开始向后便宜num个元素,即就是我们这个单词出现的那一行,然后我们解引用获得这给一行的string,并将它打印出来。



原文地址:https://www.cnblogs.com/averson/p/5150015.html