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.表达式 表达式由一 ...
随机推荐
- Python中安装numpy,scipy,matplotlib安装方法
这个吧,说简单也简单,说难吧我捣鼓了两天才弄出来,真是头发都急白了.其实只要一个网址就搞定了,嘿嘿 http://www.lfd.uci.edu 这里面有你需要的任何东西,当你运行python imp ...
- 【Lucene4.8教程之一】使用Lucene4.8进行索引及搜索的基本操作
在Lucene对文本进行处理的过程中,可以大致分为三大部分: 1.索引文件:提取文档内容并分析,生成索引 2.搜索内容:搜索索引内容,根据搜索关键字得出搜索结果 3.分析内容:对搜索词汇进行分析,生成 ...
- Android Studio默认产生Fragment
package com.edaixi.fragment; import android.content.Context;import android.net.Uri;import android.os ...
- 学习《Javascript权威指南》的第二章笔记
1.Javascript区分大小写,但是HTML不区分大小写 2.JS会忽略标识之间的空格,多数情况下也会忽视换行符,所以要采用 整齐.一致的编码风格 3.//用作结尾的注释,/* 和 */可以当跨行 ...
- Canvas基础学习(一)——实现简单时钟显示
HTML5最受欢迎的功能就是<canvas>元素.这个元素负责在页面中设定一个区域,然后就可以通过JavaScript动态地在这个区域中绘制图形.关于<canvas>元素的一些 ...
- Eloquent ORM 之关联查询
小伙伴们好,本文是在我的前一篇随笔的基础上完成的,还没有浏览的同学,请移尊驾哦 Eloquent ORM学习笔记. 前一篇文章用到了leftJoin方法,其实Eloquent对于模块之间的关联查询有自 ...
- linux之SQL语句简明教程---HAVING
那我们如何对函数产生的值来设定条件呢?举例来说,我们可能只需要知道哪些店的营业额有超过 $1,500.在这个情况下,我们不能使用 WHERE 的指令.那要怎么办呢?很幸运地,SQL 有提供一个 HAV ...
- POJ 2420 A Star not a Tree? (计算几何-费马点)
A Star not a Tree? Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3435 Accepted: 172 ...
- 小黑小波比.coding的使用
1_Coding的演示 1_html的演示 1_先查看帮助 1.它支持的语言非常多.下面是链接地址 https://coding.net/u/bobo159357456/p/html/paas/hel ...
- 滚动视差效果——background-attachment
滚动视差效果的实现原理是在同一个页面上将页面元素分为多层,例如可以分为背景.内容.贴图层,在滚动页面的时候让三者滚动的速度不一,从而在人的视觉上能够形成一种立体的近似效果.最近在做一个项目wiki的时 ...