cugwhp / OOPCPP

Learn C++ Programming Language

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TextQuery-说明

cugwhp opened this issue · comments

TextQuery - 实现过程

理解需求

需求:查询文本文件中某个单词出现在文件中的行号,并输出所在的行号。

程序设计的关键是数据+算法,对于简单的程序,我们可以从分析数据及数据流向开始。TextQuery的需求可以理解为:TextFile --Read--> vector --make_map--> map<string, set > --run_query--> set --Print--> cout.

通过以上的分析,基本上就确定了:1)程序运行的基本过程;2)函数的定义(返回值、名称、参数列表);3)构建类,满足上述功能。

下面按照搭设计类接口、主流程、函数填空这几个步骤来实现TextQuery的功能。

设计类接口

根据前面分析的结果,我们可以提炼出TextQuery类的接口。
代码如下:

#ifndef _TEXT_QUERY_H_
#define _TEXT_QUERY_H_

#include <string>
#include <fstream>
#include <set>
#include <vector>
class TextQuery
{
public:
	//构造和析构函数
	TextQuery();
	virtual ~TextQuery();
	
	//功能接口
	typedef std::vector<std::string>::size_type	line_no;	//定义类型别名
	void read_file(std::ifstream &);
	std::set<line_no>	run_query(const std::string& ) const;	//执行查询,返回行号列表
};
#endif	//#ifndef _TEXT_QUERY_H_

在这个阶段,我们重点只关注接口的输入输出参数,函数体的实现先不管。
为了保证程序流程能通过,可以在TextQuery.cpp中实现空的函数体,代码如下:

// TextQuery.cpp

#include "TextQuery.h"

TextQuery::TextQuery()
{
}

TextQuery::~TextQuery()
{    
}

bool TextQuery::read_file(ifstream& is)
{
    return false;
}

set<line_no> TextQuery::run_query(const string& strWord)
{
    return set<line_no>();
}

注意,此处的函数接口,都没有真正实现。

搭主流程

事实上,定义类的接口和搭建主流程的顺序没有明确的先后顺序,可以是在使用的过程中逐步添加的。

#include <iostream>
#include <fstream>
using namespace std;

//========================================================//
//       Text Query Function: 
// 1.打开文本文件,按行读取内容,程序保存行号和每行的内容
// 2.将每行内容按单词分解,并记录每个单词所在的行号
// 3.输入单词,能查询该单词所在的所有行号(按升序排序)
// 4.根据行号,输出包含该单词所在行的内容
//=======================================================//
int main(int argc, char** argv)
{	
	// 输入文件路径
	string		strTextFilePath;
	cout << "Input Text File Path: ";
	cin >> strTextFilePath;
	
	// 打开文本文件
	ifstream	ifs;
	ifs.open(strTextFilePath);
	if (ifs.is_open())
	{
		cerr << "Open File Failed!" << endl;
		return 2;
	}

	// 读文件内容,生成<单词-所在行>的map
	TextQuery	tq;
	tq.read_file(ifs);
	ifs.close();

	// 循环输入查询单词,输出查询结果
	while(true)
	{
		// 查询单词
		cout << "enter word to look for, or q to quit: ";
		string	str;
		cin >> str;

		// "q" is quit
		if (!cin || str=="!q")
			break;

		// 执行查询
		set<TextQuery::line_no> locs = tq.run_query(str);

		//输出查询结果
		set<TextQuery::line_no>::iterator	iter;
		for (iter=locs.begin(); iter!=locs.end(); ++iter)
			cout << *iter << "\t";
		cout << endl;
	}
	return 0;
}

自此,程序就能够正常执行了,但基本的功能未实现。

函数填空

bool read_file(std::ifstream &is)
{		//读文本文件内容,建立单词->行号map
		if (!store_file(is))
        	return false;
        	
		make_map();
		return true;
}
	
void	//读文件,一行一行地存入vector<string>
TextQuery::store_file(std::ifstream& ifs)
{
	if (!ifs.is_open())
		return false;
		
	std::string	strTextLine;
	while(std::getline(ifs, strTextLine))
		lines_of_text.push_back(strTextLine);
		
	return true;
}

void	//逐单词分解,记录每个单词出现的行号列表
TextQuery::make_map()
{
	for (line_no line_num=0; line_num!=lines_of_text.size(); ++line_num)
	{
		istringstream	line(lines_of_text[line_num]);
		string	word;
		while(line >> word)
			word_map[word].insert(line_num);
	}
}

set<TextQuery::line_no>	//执行查询
TextQuery::run_query(const std::string &query_word) const
{
	map<string, set<line_no> >::const_iterator	loc;
	loc = word_map.find(query_word);

	if (loc == word_map.end())
		return set<line_no>();
	else
		return loc->second;
}

OKAY