C++ Primer第四版 15.9 再谈文本查询 程序实现
编程过程中发现书本中的示例程序并不完全,某些地方存在错误,现已改正并添加少许注释..
1 #include<iostream>
2 #include<fstream>
#include<sstream>
#include<vector>
#include<map>
#include<set>
#include<algorithm>
#include<stdexcept>
using namespace std; class TextQuery{
public:
typedef vector<string>::size_type line_no;
void read_file(ifstream &is){
store_file(is); //读取并保存输入文件
build_map(); //创建关联单词与行号的容器
}
set<line_no> run_query(const string&) const; //根据输入的字符串,在map中查找,返回一个set集合,里面包含了该字符串在文件的所有行号
line_no size() const {return lines_of_text.size();}
string text_line(line_no) const; //以行号为输入参数,返回该行的字符串
private:
void store_file(ifstream&);
void build_map();
vector<string> lines_of_text; //容器lines_of_text保存文本的副本
map<string,set<line_no> > word_map; //first存的是单词,second存的是set集合,里面是单词所在的所有行号
}; void TextQuery::store_file(ifstream &is) //将文本文件读入内存保存在lines_of_text容器中
{
string textline;
while(getline(is,textline)) //逐行存入vector
lines_of_text.push_back(textline);
} void::TextQuery::build_map()
{
for(line_no line_num = ; line_num != lines_of_text.size(); ++line_num)
{
istringstream line(lines_of_text[line_num]); //将vector中的文件内容逐行提取出来
string word;
while(line >> word) //将每行字符串分解成单词,插入到map中,键是单词,值是行号
word_map[word].insert(line_num); //*********word_map[word]返回的是右值,是一个set对象,insert()函数是set的函数********
}
} set<TextQuery::line_no> TextQuery::run_query(const string &query_word) const
{
map<string,set<line_no> >::const_iterator loc = word_map.find(query_word);
if(loc == word_map.end())
return set<line_no>();
else
return loc->second;
} string TextQuery::text_line(line_no line) const
{
if(line < lines_of_text.size())
return lines_of_text[line];
throw std::out_of_range("line number out of range");
} string make_plural(size_t ctr, const string &word, const string &ending)
{
return (ctr == ) ? word : word + ending;
} void print_results(const set<TextQuery::line_no>& locs ,const string& sought, const TextQuery &file)
{
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size = locs.size(); //set集合的大小即是该单词出现的次数
cout<<"\n"<<sought<<" occurs "<<size<<" "<<make_plural(size,"time","s") <<endl;
line_nums::const_iterator it = locs.begin();
for(;it != locs.end(); ++it)
cout<<"\t(line"<<(*it)+<<")"<<file.text_line(*it)<<endl; //原行号从0开始,+1进行修正
} class Query_base{
friend class Query; //接口只提供给Query使用,用户和派生类只能通过Query句柄使用Query_base类
protected:
typedef TextQuery::line_no line_no;
virtual ~Query_base(){}
private:
//eval returns the |set| of lines that this Query matches
virtual std::set<line_no> eval(const TextQuery&) const = ;
//display prints the query
virtual std::ostream& display(std::ostream& = std::cout) const = ;
}; class WordQuery: public Query_base{
friend class Query;
WordQuery(const std::string &s): query_word(s) {}
std::set<line_no> eval(const TextQuery &t) const {return t.run_query(query_word);}
std::ostream& display(std::ostream &os) const {return os<<query_word;}
std::string query_word;
}; class Query{
friend Query operator~(const Query&);
friend Query operator|(const Query&, const Query&);
friend Query operator&(const Query&, const Query&); public:
Query(const std::string& word): q(new WordQuery(word)), use(new std::size_t()) { }
Query(const Query &c): q(c.q), use(c.use) {++*use;}
~Query() {decr_use();} Query& operator=(const Query&);
std::set<TextQuery::line_no> eval(const TextQuery &t) const {return q->eval(t);}
std::ostream &display(std::ostream &os) const {return q->display(os);} private:
Query(Query_base * query): q(query), use(new std::size_t()) {} //我们不希望普通用户代码定义Query_base对象。因为是private权限,操作符必须是友元
Query_base * q;
std::size_t *use;
void decr_use()
{
if(--*use == )
{
delete q;
delete use;
}
}
}; inline std::ostream& operator<<(std::ostream &os, const Query &q)
{
return q.display(os);
} class NotQuery: public Query_base{
friend Query operator~(const Query&);
NotQuery(Query q): query(q){}
std::set<line_no> eval(const TextQuery &) const;
std::ostream& display(std::ostream &os) const {return os<<"~("<<query<<")";}
const Query query; //why const?
}; class BinaryQuery: public Query_base{ //未实现eval函数,因此是一个抽象类
protected:
BinaryQuery(Query left, Query right, std::string op): lhs(left), rhs(right), oper(op) {}
std::ostream& display(std::ostream &os) const {return os<<"("<<lhs<<" "<<oper<<" "<<rhs<<")";}
const Query lhs, rhs;
const std::string oper;
}; class AndQuery: public BinaryQuery{
friend Query operator&(const Query&, const Query &);
AndQuery(Query left, Query right): BinaryQuery(left, right, "&") {}
std::set<line_no> eval(const TextQuery&) const;
}; class OrQuery: public BinaryQuery{
friend Query operator|(const Query&, const Query&);
OrQuery(Query left, Query right): BinaryQuery(left, right, "|") {}
std::set<line_no> eval(const TextQuery&) const;
}; set<TextQuery::line_no> OrQuery::eval(const TextQuery& file)const
{
set<line_no> right = rhs.eval(file),
ret_lines = lhs.eval(file);
ret_lines.insert(right.begin(), right.end());
return ret_lines;
} set<TextQuery::line_no> AndQuery::eval(const TextQuery& file) const
{
set<line_no> left = lhs.eval(file),
right = rhs.eval(file);
set<line_no> ret_lines;
set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(ret_lines, ret_lines.begin())); //调用STL库函数进行容器的交集操作
return ret_lines;
} set<TextQuery::line_no> NotQuery::eval(const TextQuery& file) const //const引用的对象,只能访问对象的const成员,所以size函数必须是const类型的
{
set<TextQuery::line_no> has_val = query.eval(file);
set<line_no> ret_lines;
for(TextQuery::line_no n = ; n != file.size(); ++n)
if(has_val.find(n) == has_val.end())
ret_lines.insert(n);
return ret_lines;
} inline Query operator~(const Query &oper)
{
return new NotQuery(oper); //等价于Query_base * tmp = new NotQuery(oper); return Query(tmp);
} inline Query operator|(const Query &lhs, const Query &rhs)
{
return new OrQuery(lhs,rhs);
} inline Query operator&(const Query &lhs, const Query &rhs)
{
return new AndQuery(rhs,lhs);
} int main()
{
ifstream infile;
infile.open("C:\\1.txt");
if(!infile)
{
std::cout<<"Cannot open file"<<std::endl;
exit();
}
TextQuery tq;
tq.read_file(infile); /* 该处填写要查找的内容逻辑表达式 */
//set<TextQuery::line_no> locs = tq.run_query(s);
//Query q = ~(Query("today") & Query("API"));
Query q = Query("today is") & Query("and");
set<TextQuery::line_no> locs = q.eval(tq);
string s = "";
print_results(locs,s,tq);
return ;
}
当然要想实现作者开头所展示的实时查询功能,还要下不少功夫,有能力的童鞋自己实现字符串的解析吧-_-
C++ Primer第四版 15.9 再谈文本查询 程序实现的更多相关文章
- C++ Primer 学习笔记_38_STL实践与分析(12)--集成的应用程序容器:文本查询程序
STL实践与分析 --容器的综合应用:文本查询程序 引言: 本章中最重点的实例.由于不须要用到multiset与multimap的内容.于是将这一小节提到了前面.通过这个实例程序,大师分析问题的智慧, ...
- GoF设计模式三作者15年后再谈模式
Erich Gamma, Richard Helm, 和 Ralph Johnson在GoF设计模式发表15年以后,再谈模式,另外一位作者,也是四色原型的发明者Peter已经过世. 提问者:如今有85 ...
- C++学习书籍推荐《C++ Primer 第四版》下载
百度云及其他网盘下载地址:点我 编辑推荐 <C++ Primer中文版(第4版)>对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使<C++ Primer中文版 ...
- C++ primer 第四版 练习3.13,3.14
读一组整数到 vector 对象,计算并输出每对相邻元素的 和.如果读入元素个数为奇数,则提示用户后一个元素 没有求和,并输出其值. vector<int> ivec; int ival; ...
- C++_系列自学课程_第_12_课_语句_《C++ Primer 第四版》
前面的文章说完了表达式和类型转换的部分内容,在我参考的书里面,接下来讨论的是各种语句,包括:顺序语句.声明语句.复合语句(块语句).语句作用域 .if语句.while语句.for语句.do...whi ...
- Java虚拟机15:再谈四种引用状态
JVM的四种引用状态 在Java虚拟机5:Java垃圾回收(GC)机制详解一文中,有简单提到过JVM的四种引用状态,当时只是简单学习,知道有这么一个概念,对四种引用状态理解不深.这两天重看虚拟机这部分 ...
- C++ Primer 第四版阅读笔记
阅读笔记 初始化 变量定义指定了变量的类型和标识符,也可以为对象提供初始值.定义时指定了初始值的对象被称为是 已初始化的.C++ 支持两种初始化变量的形式:复制初始化和 直接初始化.复制初始化语法用等 ...
- C++_系列自学课程_第_11_课_类型转换_《C++ Primer 第四版》
上次说了关于表达式的一些内容,说到还有一些关于数据类型转换的内容,今天我们接着八一八C++中的数据类型转换. 一.隐式类型转换 在表达式中,有些操作符可以对多种类型的操作数进行操作, 例如 + 操作符 ...
- C++_系列自学课程_第_10_课_表达式_《C++ Primer 第四版》
程序设计语言中大部分程序都在进行表达式的求值操作, 例如求两个数的和,求一个表达式的逻辑结果,或者通过输入输出表达式语句进行输入和输出. 这里我们对表达式进行讨论. 一.表达式 1.表达式 表达式由一 ...
随机推荐
- study notes: high performance linux server programming
1:linux网络API分为:socker地址API,socker基础API,网络信息API 1,socker地址API:包含IP地址和端口(ip, port).表示TCP通信的一端. 2,socke ...
- php variance
function variance ($a) { /** variable and initializations */ $the_variance = 0.0; $the_mean = 0.0; $ ...
- Bower安装
一.安装Node.js: 1.下载Node.js并安装: http://nodejs.org/ 2.双击安装,默认C盘:C:\Program Files\nodejs 3.cmd进入上述目录: ...
- 【Android 错误记录】installation error: INSTALL_PARSE_FAILED_NO_CERTIFICATES 错误
在运行android应用的时候报出了如题的错误: installation error: INSTALL_PARSE_FAILED_NO_CERTIFICATES 原因之一:在src源文件目录下面,有 ...
- Berkeley DB基础教程
一.Berkeley DB的介绍 (1)Berkeley DB是一个嵌入式数据库,它适合于管理海量的.简单的数据.如Google使用其来保存账户信息,Heritrix用其来保存froniter. (2 ...
- 在Javascript中使用String.startsWith和endsWith
在Javascript中使用String.startsWith和endsWith 在操作字符串(String)类型的时候,startsWith(anotherString)和endsWith(anot ...
- thinkphp微信开发:安全模式消息加解密
使用thinkphp官方的WeChat包,使用不同模式可以成功,但是安全模式就是不行,现将分析解决结果做下记录. TRight 分析问题: 解密微信服务器消息老是不成功,下载下微信公众平台官方给出的解 ...
- mac10.9 设置vim tab
vimrc系统文件目录 /usr/share/vim 在vimrc中添加以下代码后,重启vim即可实现按TAB产生4个空格:set ts=4 (注:ts是tabstop的缩写,设TAB宽4个空格)s ...
- Python中metaclass解释
Classes as objects 首先,在认识metaclass之前,你需要认识下python中的class.python中class的奇怪特性借鉴了smalltalk语言.大多数语言中,clas ...
- Web.config中rewite 节点引起的500.19错误
刚刚接手一个外包的小项目,客户给了发布后的网站文件和数据库,想在本地搭建一套环境先运行下看看网站原有的效果.数据库还原什么都弄好了,数据库字符串也配置好,部署在本地IIS里面,访问了下,结果看到的是5 ...