C++文本查询程序(智能指针)

文本查询程序

在一个指定的文件中查询单词,查询结果是单词在文章中总共出现的次数,以及在所在行的列表,如果一个单词在一行出现多次,则只记录一次,行会按照升序输出。

打印示例:
在这里插入图片描述

文本查询程序设计

  1. 使用**vector< string >**存储整个读入文件的拷贝,每行保存为vector的一个元素,利用vector的下标操作来访问每一行。
  2. 使用istringstream来拆解每一行变为单词。
  3. 使用set保存每个单词在输入文本中出现的行号。保证了每行只出现了一次且行号按升序保存。
  4. 使用map来将每个单词与它所出现的行号set关联起来。

数据结构:

  • 使用vector存储文件内容
  • map关键字为要查询的单词,值为set<size_t> ,表示所在的行号。
vector<string> file;		//读取文件
map<string,set<size_t>>;	//关键字:值  = 单词:出现的行号

【代码】:不使用类的版本

	string file_name;
	cout << "输入文件名:";
	cin >> file_name;
	ifstream in_file(file_name);
	if (!in_file.is_open())
	{
		cerr << "文件打开失败!\n";
		exit(-1);
	}

	vector<string> vec;
	map<string, set<size_t>> MAP;

	string text_str;
	while (getline(in_file,text_str))	//读取每一行,存储在vector的每一个元素
	{
		vec.push_back(text_str);
	}
	for (size_t i = 0; i < vec.size(); ++i)
	{
		cout << vec[i] << endl;
	} 
	string research;
	string word;
	while ([&]()->bool{ cout << "请输入你要查询的单词(输入quit退出): "; return (cin >> research && research != "quit"); }())
	{
		for (size_t i = 0; i < vec.size(); ++i)
		{
			istringstream line_str(vec[i]);	//读取每一行
			while (line_str >> word)
			{
				if (research == word)
				{
					MAP[word].insert(i);	// 单词:行号
					break;
				}
			}
		}
        //注意此处MAP里面存储了要查询的单词,其值为对应的行号,遍历行号,根据行号打印出对应在vector里的行内容
		cout << "element occurs " << MAP[research].size() << " times" << endl;
		for (auto it = MAP[research].cbegin(); it != MAP[research].cend(); ++it)
		{
			cout << '\t' << "(line " << *it << ") " << vec[*it] << endl;
		}
	}

【代码】:使用类(在类之间共享数据)

我们需要在TextQuery类中读取数据,在TextResult类中打印数据
我们不妨利用shared_ptr来共享数据:(关于shared_ptr及其他智能指针,请看:我写的动态分配与智能指针博文

  • 将TextQuery中读取的文件内容的vector作为shared_ptr来共享到TextResult中,方便打印时遍历文件。
  • 将TextQuery中读取的map集合的set作为shared_ptr来共享到TextResult中,这样就可以直接获得单词在的行号,根据shared_ptr中vector共享的内容,就可以直接读文件内容。
  • 在TextResult的一个构造函数中可以直接共享数据。

读取内容的类:

shared_ptr<vector<string>> file;			//拷贝文件内容
map<string, shared_ptr<set<line_NO>>> wm;	//每个单词和它所出现的行号

共享到 打印内容的类:

string research;					//查询的单词
shared_ptr <set<line_NO>> lines;	//出现的行号,set集合
shared_ptr <vector<string>> file;	//输入文件,vector容器




完整代码及测试:

using line_NO = vector<string>::size_type;
class QueryResult;	//前向声明
class TextQuery		//读取类
{
public:
	
	//读取指定输入的构造函数
	TextQuery(ifstream& i_file);
	//查询操作
	QueryResult query(const string& word)const;	//函数作用是:将读入的数据传给打印的类。
private:
	shared_ptr<vector<string>> file;			//拷贝文件内容
	map<string, shared_ptr<set<line_NO>>> wm;	//每个单词和它所出现的行号

};

class QueryResult	//打印类
{
	friend ostream& print(ostream& os, const QueryResult& q);	//作为类的友元函数
public:
	QueryResult(string s, shared_ptr<set<line_NO>> p, shared_ptr<vector<string>> f)
		:research(s), lines(p), file(f) {}	//接受来自读取的类的数据
private:
	string research;					//查询单词
	shared_ptr <set<line_NO>> lines;	//出现的行号,set集合
	shared_ptr <vector<string>> file;	//输入文件,vector容器
};


TextQuery::TextQuery(ifstream& i_file) :file(new vector<string>)
{
	string text;
	while (getline(i_file, text))
	{
		file->push_back(text);	//文件每一行存入vector
		auto No = file->size() - 1;
		istringstream line(text);	//读取这一行
		string word;
		while (line >> word)
		{
			//读取行的每个单词
			auto& lines = wm[word];//lines是一个shared_ptr
			if (!lines)
			{
				lines.reset(new set<line_NO>);	//分配一个新的set
			}
			lines->insert(No);	//将此行号插入到set中
		}
	}

}

QueryResult TextQuery::query(const string& word) const
{
	//未找到查询单词,定义一个空的set,
	static shared_ptr<set<line_NO>> nodata(new set<line_NO>);
	auto loc = wm.find(word);	//查找关键字
	if (loc == wm.end())		//返回一个指向这个关键字对应的所有的值的map迭代器
	{
		return QueryResult(word, nodata, file);	//将空set传入,表示未找到
	}
	else
	{
		return QueryResult(word, loc->second, file);	//传入关键字对应的set集合
	}
}

ostream& print(ostream& os, const QueryResult& q)
{
	//找到了单词,打印出现次数和所出现的位置
	//set的size成员函数返回set关键字的个数
	os << q.research << " occurs " << q.lines->size() << endl;	
	for (auto num : *q.lines)				//得到在set中对应的行号
	{
		//在文件中根据获得的行号来打印
		os << "\t(line " << num + 1 << ") " << *(q.file->begin() + num) << endl;
	}
	return os;
}
int main()
{
	ifstream in_file("111.txt");
	TextQuery tq(in_file);
	while (true)
	{
		cout << "请输入要查询的单词,输入quit退出: ";
		string word;
		if (!(cin >> word) || word== "quit")
		{
			break;
		}
		print(cout, tq.query(word)) << endl;
	}
	return 0;
}

在这里插入图片描述

posted @ 2022-08-17 10:32  hugeYlh  阅读(17)  评论(0编辑  收藏  举报  来源