编程过程中发现书本中的示例程序并不完全,某些地方存在错误,现已改正并添加少许注释..

  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 再谈文本查询 程序实现的更多相关文章

  1. C++ Primer 学习笔记_38_STL实践与分析(12)--集成的应用程序容器:文本查询程序

    STL实践与分析 --容器的综合应用:文本查询程序 引言: 本章中最重点的实例.由于不须要用到multiset与multimap的内容.于是将这一小节提到了前面.通过这个实例程序,大师分析问题的智慧, ...

  2. GoF设计模式三作者15年后再谈模式

    Erich Gamma, Richard Helm, 和 Ralph Johnson在GoF设计模式发表15年以后,再谈模式,另外一位作者,也是四色原型的发明者Peter已经过世. 提问者:如今有85 ...

  3. C++学习书籍推荐《C++ Primer 第四版》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <C++ Primer中文版(第4版)>对C++基本概念和技术全面而且权威的阐述,对现代C++编程风格的强调,使<C++ Primer中文版 ...

  4. C++ primer 第四版 练习3.13,3.14

    读一组整数到 vector 对象,计算并输出每对相邻元素的 和.如果读入元素个数为奇数,则提示用户后一个元素 没有求和,并输出其值. vector<int> ivec; int ival; ...

  5. C++_系列自学课程_第_12_课_语句_《C++ Primer 第四版》

    前面的文章说完了表达式和类型转换的部分内容,在我参考的书里面,接下来讨论的是各种语句,包括:顺序语句.声明语句.复合语句(块语句).语句作用域 .if语句.while语句.for语句.do...whi ...

  6. Java虚拟机15:再谈四种引用状态

    JVM的四种引用状态 在Java虚拟机5:Java垃圾回收(GC)机制详解一文中,有简单提到过JVM的四种引用状态,当时只是简单学习,知道有这么一个概念,对四种引用状态理解不深.这两天重看虚拟机这部分 ...

  7. C++ Primer 第四版阅读笔记

    阅读笔记 初始化 变量定义指定了变量的类型和标识符,也可以为对象提供初始值.定义时指定了初始值的对象被称为是 已初始化的.C++ 支持两种初始化变量的形式:复制初始化和 直接初始化.复制初始化语法用等 ...

  8. C++_系列自学课程_第_11_课_类型转换_《C++ Primer 第四版》

    上次说了关于表达式的一些内容,说到还有一些关于数据类型转换的内容,今天我们接着八一八C++中的数据类型转换. 一.隐式类型转换 在表达式中,有些操作符可以对多种类型的操作数进行操作, 例如 + 操作符 ...

  9. C++_系列自学课程_第_10_课_表达式_《C++ Primer 第四版》

    程序设计语言中大部分程序都在进行表达式的求值操作, 例如求两个数的和,求一个表达式的逻辑结果,或者通过输入输出表达式语句进行输入和输出. 这里我们对表达式进行讨论. 一.表达式 1.表达式 表达式由一 ...

随机推荐

  1. Masstransit开发基于消息传递的分布式应用

    使用Masstransit开发基于消息传递的分布式应用 Masstransit作为.Net平台下的一款优秀的开源产品却没有得到应有的关注,这段时间有机会阅读了Masstransit的源码,我觉得我有必 ...

  2. 正式学习React(五) Reactjs 的 PropTypes 使用方法

    propTypes 使用來規範元件Props的型別與必需狀態 var Test = React.createClass({ propTypes: { // required requiredFunc: ...

  3. ASP.net(C#)批量上传图片(完整版)

    摘自:http://www.biye5u.com/article/netsite/ASPNET/2010/1996.html   这篇关于ASP.Net批量上传图片的文章写得非常好,偶尔在网上看到想转 ...

  4. 山寨QQ音乐的布局(一)

    学了两天IOS趁着还没忘光,巩固一下所学知识想做点东西,由于自己的设计能力有限,所以就山寨一下吧,说到山寨怎么能忘了腾讯呢,今天发现QQ音乐的设计风格是扁平化的,小清新风格,所以就山寨一下它吧.. 由 ...

  5. 'adb' 不是内部或外部命令,也不是可运行的程序

    启动adb shell的时候,出现如下问题: 'adb' 不是内部或外部命令,也不是可运行的程序或批处理文件. 在确保自己的SDK安装正确的时候,就很好办了,找到SDK安装目录\platform-to ...

  6. Excel导入到DataTable

    1.前台代码 <asp:FileUpload ID="fupFiles" runat="server" /> <asp:Button ID=& ...

  7. 2.2.2 胸腰差和胸臀差的应用_米人NOONE_新浪博客

    2.2.2  胸腰差和胸臀差的应用_米人NOONE_新浪博客 腰差和胸臀差的应用(2009-06-16 19:24:57)转载▼标签:校园         前面已经对这两个概念作了简单的讲解.这两个概 ...

  8. flume【源码分析】分析Flume的拦截器

    h2 { color: #fff; background-color: #7CCD7C; padding: 3px; margin: 10px 0px } h3 { color: #fff; back ...

  9. OC基础1:一些基本概念

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.关于类方法和实例方法: (1).类方法 ...

  10. Xcode8 注释快捷键无效, 解决方案

    这个是因为苹果解决xcode ghost.把插件屏蔽了.解决方法命令运行: sudo /usr/libexec/xpccachectl 然后必须重启电脑后生效