您的位置:首页 > 编程语言 > C语言/C++

标准库+类——实现文本查询

2015-07-14 11:11 447 查看
       程序允许用户在一个给定的文件中查询单词。查询结果是:单词在文件中的出现次数,以及其所在行的文本的列表。

main.cpp:主程序

<span style="font-size:18px;">//标准库+类————文本查询程序
//程序目的:允许一个用户在一个给定的文件中查询单词,
//查询结果是(1)单词在文件中出现的次数以及(2)其所在行的列表(行号+该行全部文本)、

/*
开始一个程序设计,一种好方法就是从需求出手,列出程序的操作。了解需要哪些操作会帮助
我们分析出需要什么的数据结构。

vector<string>:用来保存整个文件的一份拷贝。输入文件的每行保存为vector的一个元素;
istringstream:将每行分解为单词;
set:用来保存每个单词出现在输入文本中出现的行号;保证每行只出现一次且升序排列
map:用来将每个单词与出现的行号set关联起来;方便提取任意单词的set;
textQuery类:一个用来读取输入文件的构造函数,一个查询操作;
queryResult类:保存打印结果(出现了多少次,行号,及该行文本),并打印结果;

*/
#include"base.h"

void main()
{
ifstream text("..\\infiles.txt");//待查找文件放在该源程序的上一级目录
runQureies(text);
}</span>


base.h:类的声明

#ifndef BASE_H//头文件保护符————确保头文件多次包含仍能安全工作的常用技术是:预处理器
#define BASE_H

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

using namespace std;

class queryResult;//为了定义函数query的返回类型,这个定义是必须的
class textQuery
{
public:
using line_no = vector<string> ::size_type;//类型别名

textQuery(ifstream &);
~textQuery() {};//~textQuery()刚开始没写{},出现了error LINK2019的错误
queryResult query(const string &) const;

private:
shared_ptr<vector<string> > file; //输入文件
map<string, shared_ptr<set<line_no> > > wm; //每个单词到它对应的行号的映射
};

//在textQuery类型的对象中保存着行号set以及这些行对应的文本
//queryResult类要表达查询的结果,这就需要数据共享
//(1)拷贝行号的set,这样做很耗时;
//(2)拷贝vector,可能引起整个文本的拷贝,而我们的目标只是文本的一小部分
//通过返回指向textQuery对象内部的的迭代器(或者指针),可以避免拷贝
class queryResult
{
friend ostream & print(ostream &, const queryResult &);

public:
queryResult(string s, shared_ptr<set<textQuery::line_no> > p, shared_ptr<vector <string>> f) :
sought(s), lines(p), file(f) { }//构造函数:将参数保存在对应的数据成员中

private:
string sought; //待查询单词
shared_ptr<set<textQuery::line_no>> lines; //出现的行号
shared_ptr<vector<string>> file; //输入文件
};

void runQureies(ifstream &infile);
#endif

base.cpp:类的定义实现
#include"base.h"
#include<sstream>

textQuery::textQuery(ifstream & is) :file(new vector<string>)
{
string text;
while (getline(is, text)) //对文件中的每一行
{
file->push_back(text); //当前文本
int n = file->size() - 1; //当前行号
istringstream line(text); //将行文本分解为单词
string word;
while (line >> word) //对行中的每个单词
{
auto &lines = wm[word];
if (!lines)//在我们第一次遇到这个单词时候,这个指针为空
lines.reset(new set<line_no>);//分配一个新的set
lines->insert(n);//将此行号插入set中
}
}
}

//query的返回类型是一个queryResult
queryResult textQuery::query(const string & sought) const
{
//如果未找到给定的string,就没可返回的set。
//为此,定义一个局部static对象,它是指向一个指向空的行号set的shared_ptr。
static shared_ptr<set<line_no>> nodata(new set<line_no>);
//使用find而不是下标运算符来查找单词,避免将单词添加到wm中
auto loc = wm.find(sought);
if (loc == wm.end())
{
return queryResult(sought, nodata, file); //未找到,返回空!
}
else
return queryResult(sought, loc->second, file);

}

ostream & print(ostream &os, const queryResult & qr)
{
//找到!打印!
os << qr.sought << " occurs " << qr.lines->size() << " "
<< (qr.lines->size() > 1 ? "times" : "time") << endl;

//行号+1是为了防止行号从0开始,避免用户迷惑
for (auto num : *qr.lines)
os << "\t(line " << num + 1 << ")" << *(qr.file->begin() + num) << endl;
return os;
}

void runQureies(ifstream &infile)
{
textQuery tq(infile);//保存待查询文件,并建立map

while (true)
{
cout << "Enter the word to look for, or 'q' to quit:";
string s; //待查询单词
if (!(cin >> s) || s == "q")
break;
//指向查询并打印结果
print(cout, tq.query(s)) << endl; //print函数返回值是一个ostream &
}
}
打印结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息