C++使用标准库--文本查询程序

题目:在给定文件中查询单词。查询结果是单词在文件中出现的次数及所在行的列表。如果一个单词在一行中多次出现,此行只显示一次,行会按照升序输出。

效果如下:


在此程序的实现中使用到的标准库内容包括:

(1)ifstream:用来绑定并打开指定的文本。

(2)vector<string>:用来保存整个文本,每行保存为vector中的元素。

(3)istringstream:用来将每行分解为单词。

(4)multiset:用来保存每个单词出现的行号,保证了行号按升序排列;一个单词在某行中出现多次,行号会重复保存;

(5)set:用来将multiset中的重复去除,用于一个单词在某行中出现多次,只显示一次;

(6)map:将单词和它出现的行号的multiset关联起来。

(7)shared_ptr:用于在类之间进行数据共享;


设计思想:

1.当我们设计一个类时,在真正实现成员之前先编写程序使用这个类,是一种非常有用的方法。通过这种方法,可以看到类是否具有我们所需要的操作。

2.在类的设计过程中,最重要的就是接口的设计,也就是头文件的设计。


注意的问题:

1.IO对象无拷贝或赋值,需要以引用的方式传递参数和返回流。

2.auto& lines = wm[word];这里也需要是按引用传递,否则会发生拷贝,不能操作map中的set,结果为空。


源代码与C++Primer(第5版)第十二章给出的稍有改动,我认为书中讲的统计单词出现次数的方法不合理。



1.main.cpp

#include "TxtQuery.h"
#include "queryResult.h"
#include "iostream"

void runQueries(std::ifstream& infile)
{
	TxtQuery wordQuery(infile);
	while (true)
	{
		std::cout<< "enter word to look for, or q to quit:";
		std::string word;
		if (!(std::cin >> word) || word == "q") break;
		print(std::cout, wordQuery.query(word));
	}
}

int main()
{
	std::ifstream infile("1.txt");
	runQueries(infile);
}


2.TxtQuery.h
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <map>
#include <set>
#include <fstream>
#include "queryResult.h"


class TxtQuery
{
public:
	TxtQuery();
	~TxtQuery();
	TxtQuery(std::ifstream& in);
	queryResult query(const std::string& word);
private:
	std::shared_ptr<std::vector<std::string>> file;
	std::map<std::string, std::shared_ptr<std::multiset<int>>> wm;

};


3. TxtQuery.cpp

#include "TxtQuery.h"
#include <sstream>

TxtQuery::TxtQuery()
{
}


TxtQuery::~TxtQuery()
{
}

TxtQuery::TxtQuery(std::ifstream& in) :file(new std::vector<std::string>) 
{
	std::string text;
	while (std::getline(in, text))
	{
		file->push_back(text);
		int n = file->size();
		std::istringstream line(text);
		std::string word;
		while (line >> word)
		{
			auto& lines = wm[word];
			if (!lines)
			{
				lines.reset(new std::multiset<int>);
			}
			lines->insert(n);
		}
	}
}

queryResult TxtQuery::query(const std::string& word)
{
	static std::shared_ptr<std::multiset<int>> nodata(new std::multiset<int>);
	auto loc = wm.find(word);
	if(loc == wm.end())
	{ 
		return queryResult(word, nodata, file);
	}
	else
	{
		return queryResult(word, loc->second, file);
	}
}

4、queryResult.h

#pragma once
#include <string>
#include <memory>
#include <set>
#include <vector>
class queryResult
{
public:
	queryResult();
	~queryResult();
	queryResult(const std::string sought, std::shared_ptr<std::multiset<int>> lines, std::shared_ptr<std::vector<std::string>> file)	:
		sought(sought)
		,lines(lines)
		,file(file)	{}
	friend std::ostream& print(std::ostream&, const queryResult&);
private:
	std::string sought;
	std::shared_ptr<std::multiset<int>> lines;
	std::shared_ptr<std::vector<std::string>> file;
};


5、 queryResult.cpp
#include "queryResult.h"
#include <iostream>

queryResult::queryResult()
{
}

queryResult::~queryResult()
{
}

std::ostream& print(std::ostream& os, const queryResult& qr)
{
	os << qr.sought << " occurs " << qr.lines->size() << " " << "times" << std::endl;
	
	//用multiset初始化set,重复的内容自动去除
	std::set<int> single(std::begin(*qr.lines), end(*qr.lines));
	for (auto num : single) {
		os << "\t(line " << num << ")" << *(qr.file->begin() + num - 1) << std::endl;
	}
	std::cout << std::endl;
	return os;
}


发布了89 篇原创文章 · 获赞 210 · 访问量 47万+

猜你喜欢

转载自blog.csdn.net/i_chaoren/article/details/78698422