C++ Primer第四版 15.9 再谈文本查询 程序实现

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

  1 #include<iostream>    2 #include<fstream>
  3 #include<sstream>
  4 #include<vector>
  5 #include<map>
  6 #include<set>
  7 #include<algorithm>
  8 #include<stdexcept>
  9 using namespace std;
 10
 11 class TextQuery{
 12 public:
 13     typedef vector<string>::size_type line_no;
 14     void read_file(ifstream &is){
 15         store_file(is);     //读取并保存输入文件
 16         build_map();     //创建关联单词与行号的容器
 17     }
 18     set<line_no> run_query(const string&) const;    //根据输入的字符串,在map中查找,返回一个set集合,里面包含了该字符串在文件的所有行号
 19     line_no size() const {return lines_of_text.size();}
 20     string text_line(line_no) const;     //以行号为输入参数,返回该行的字符串
 21 private:
 22     void store_file(ifstream&);
 23     void build_map();
 24     vector<string> lines_of_text;    //容器lines_of_text保存文本的副本
 25     map<string,set<line_no> > word_map;    //first存的是单词,second存的是set集合,里面是单词所在的所有行号
 26 };
 27
 28
 29 void TextQuery::store_file(ifstream &is)    //将文本文件读入内存保存在lines_of_text容器中
 30 {
 31     string textline;
 32     while(getline(is,textline))     //逐行存入vector
 33     lines_of_text.push_back(textline);
 34 }
 35
 36
 37 void::TextQuery::build_map()
 38 {
 39     for(line_no line_num = 0; line_num != lines_of_text.size(); ++line_num)
 40     {
 41         istringstream line(lines_of_text[line_num]);    //将vector中的文件内容逐行提取出来
 42         string word;
 43         while(line >> word)     //将每行字符串分解成单词,插入到map中,键是单词,值是行号
 44         word_map[word].insert(line_num);     //*********word_map[word]返回的是右值,是一个set对象,insert()函数是set的函数********
 45     }
 46 }
 47
 48
 49 set<TextQuery::line_no> TextQuery::run_query(const string &query_word) const
 50 {
 51     map<string,set<line_no> >::const_iterator loc = word_map.find(query_word);
 52     if(loc == word_map.end())
 53         return set<line_no>();
 54     else
 55         return loc->second;
 56 }
 57
 58
 59 string TextQuery::text_line(line_no line) const
 60 {
 61     if(line < lines_of_text.size())
 62         return lines_of_text[line];
 63     throw std::out_of_range("line number out of range");
 64 }
 65
 66
 67 string make_plural(size_t ctr, const string &word, const string &ending)
 68 {
 69     return (ctr == 1) ? word : word + ending;
 70 }
 71
 72
 73 void print_results(const set<TextQuery::line_no>& locs ,const string& sought, const TextQuery &file)
 74 {
 75     typedef set<TextQuery::line_no> line_nums;
 76     line_nums::size_type size = locs.size();    //set集合的大小即是该单词出现的次数
 77     cout<<"\n"<<sought<<" occurs "<<size<<" "<<make_plural(size,"time","s") <<endl;
 78     line_nums::const_iterator it = locs.begin();
 79     for(;it != locs.end(); ++it)
 80         cout<<"\t(line"<<(*it)+1<<")"<<file.text_line(*it)<<endl;    //原行号从0开始,+1进行修正
 81 }
 82
 83
 84 class Query_base{
 85     friend class Query; //接口只提供给Query使用,用户和派生类只能通过Query句柄使用Query_base类
 86 protected:
 87     typedef TextQuery::line_no line_no;
 88     virtual ~Query_base(){}
 89 private:
 90     //eval returns the |set| of lines that this Query matches
 91     virtual std::set<line_no> eval(const TextQuery&) const = 0;
 92     //display prints the query
 93     virtual std::ostream& display(std::ostream& = std::cout) const = 0;
 94 };
 95
 96 class WordQuery: public Query_base{
 97     friend class Query;
 98     WordQuery(const std::string &s): query_word(s) {}
 99     std::set<line_no> eval(const TextQuery &t) const {return t.run_query(query_word);}
100     std::ostream& display(std::ostream &os) const {return os<<query_word;}
101     std::string query_word;
102 };
103
104 class Query{
105     friend Query operator~(const Query&);
106     friend Query operator|(const Query&, const Query&);
107     friend Query operator&(const Query&, const Query&);
108
109 public:
110     Query(const std::string& word): q(new WordQuery(word)), use(new std::size_t(1)) { }
111     Query(const Query &c): q(c.q), use(c.use) {++*use;}
112     ~Query() {decr_use();}
113
114     Query& operator=(const Query&);
115     std::set<TextQuery::line_no> eval(const TextQuery &t) const {return q->eval(t);}
116     std::ostream &display(std::ostream &os) const {return q->display(os);}
117
118 private:
119     Query(Query_base * query): q(query), use(new std::size_t(1)) {} //我们不希望普通用户代码定义Query_base对象。因为是private权限,操作符必须是友元
120     Query_base * q;
121     std::size_t *use;
122     void decr_use()
123     {
124         if(--*use == 0)
125         {
126             delete q;
127             delete use;
128         }
129     }
130 };
131
132 inline std::ostream& operator<<(std::ostream &os, const Query &q)
133 {
134     return q.display(os);
135 }
136
137 class NotQuery: public Query_base{
138     friend Query operator~(const Query&);
139     NotQuery(Query q): query(q){}
140     std::set<line_no> eval(const TextQuery &) const;
141     std::ostream& display(std::ostream &os) const {return os<<"~("<<query<<")";}
142     const Query query;              //why const?
143 };
144
145 class BinaryQuery: public Query_base{   //未实现eval函数,因此是一个抽象类
146 protected:
147     BinaryQuery(Query left, Query right, std::string op): lhs(left), rhs(right), oper(op) {}
148     std::ostream& display(std::ostream &os) const {return os<<"("<<lhs<<" "<<oper<<" "<<rhs<<")";}
149     const Query lhs, rhs;
150     const std::string oper;
151 };
152
153 class AndQuery: public BinaryQuery{
154     friend Query operator&(const Query&, const Query &);
155     AndQuery(Query left, Query right): BinaryQuery(left, right, "&") {}
156     std::set<line_no> eval(const TextQuery&) const;
157 };
158
159
160 class OrQuery: public BinaryQuery{
161     friend Query operator|(const Query&, const Query&);
162     OrQuery(Query left, Query right): BinaryQuery(left, right, "|") {}
163     std::set<line_no> eval(const TextQuery&) const;
164 };
165
166 set<TextQuery::line_no> OrQuery::eval(const TextQuery& file)const
167 {
168     set<line_no> right = rhs.eval(file),
169              ret_lines = lhs.eval(file);
170     ret_lines.insert(right.begin(), right.end());
171     return ret_lines;
172 }
173
174 set<TextQuery::line_no> AndQuery::eval(const TextQuery& file) const
175 {
176     set<line_no> left = lhs.eval(file),
177                 right = rhs.eval(file);
178     set<line_no> ret_lines;
179     set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(ret_lines, ret_lines.begin())); //调用STL库函数进行容器的交集操作
180     return ret_lines;
181 }
182
183 set<TextQuery::line_no> NotQuery::eval(const TextQuery& file) const     //const引用的对象,只能访问对象的const成员,所以size函数必须是const类型的
184 {
185     set<TextQuery::line_no> has_val = query.eval(file);
186     set<line_no> ret_lines;
187     for(TextQuery::line_no n = 0; n != file.size(); ++n)
188         if(has_val.find(n) == has_val.end())
189             ret_lines.insert(n);
190     return ret_lines;
191 }
192
193
194 inline Query operator~(const Query &oper)
195 {
196     return new NotQuery(oper);              //等价于Query_base * tmp = new NotQuery(oper); return Query(tmp);
197 }
198
199 inline Query operator|(const Query &lhs, const Query &rhs)
200 {
201     return new OrQuery(lhs,rhs);
202 }
203
204 inline Query operator&(const Query &lhs, const Query &rhs)
205 {
206     return new AndQuery(rhs,lhs);
207 }
208
209
210 int main()
211 {
212     ifstream infile;
213     infile.open("C:\\1.txt");
214     if(!infile)
215     {
216         std::cout<<"Cannot open file"<<std::endl;
217         exit(1);
218     }
219     TextQuery tq;
220     tq.read_file(infile);
221
222         /* 该处填写要查找的内容逻辑表达式 */
223         //set<TextQuery::line_no> locs = tq.run_query(s);
224         //Query q = ~(Query("today") & Query("API"));
225         Query q = Query("today is") & Query("and");
226         set<TextQuery::line_no> locs = q.eval(tq);
227         string s = "";
228         print_results(locs,s,tq);
229  return 0;
230 }

当然要想实现作者开头所展示的实时查询功能,还要下不少功夫,有能力的童鞋自己实现字符串的解析吧-_-

时间: 2024-10-06 05:59:45

C++ Primer第四版 15.9 再谈文本查询 程序实现的相关文章

C++ Primer 学习笔记_73_面向对象编程 --再谈文本查询示例

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

C++ Primer 学习笔记_74_面向对象编程 --再谈文本查询示例[续/习题]

面向对象编程 --再谈文本查询示例[续/习题] //P522 习题15.41 //1 in TextQuery.h #ifndef TEXTQUERY_H_INCLUDED #define TEXTQUERY_H_INCLUDED #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <set> #include <map&g

C++ Primer 学习笔记_73_面向对象编程 -再谈文本查询示范

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

C++ Primer 学习笔记_74_面向对象编程 -再谈文本查询示范[续/习题]

面向对象编程 --再谈文本查询示例[续/习题] //P522 习题15.41 //1 in TextQuery.h #ifndef TEXTQUERY_H_INCLUDED #define TEXTQUERY_H_INCLUDED #include <iostream> #include <fstream> #include <sstream> #include <vector> #include <set> #include <map&g

C++ Primer 第四版中文完整版 和答案完整版

前段时间下载的C++Primer 第四版中文版 缺少第十到第十三章,终于下到了完整版的电子书还找到了完整的配套答案. 全部供大家免费下载: 下面是链接: 由于CSDN限制文件的大小所以C++primer 分了两个文件 还有答案是一个文件: http://download.csdn.net/my C++ Primer 第四版中文完整版 和答案完整版,布布扣,bubuko.com

【足迹C++primer】41、文本查询程序

/** * 功能:使用标准库:文本查询程序 * 时间:2014年7月10日09:10:15 * 作者:cutter_point */ #include<iostream> #include<map> #include<set> #include<fstream> #include<sstream> #include<string> #include<vector> #include<memory> using

第十四篇:一个文本查询程序的实现

前言 本文将讲解一个经典的文本查询程序,对前面所学的容器相关知识进行一个从理论到实际的升华,同时也对即将学习的面向对象知识来一次初体验. 程序描述 要求实现这样一个程序:读取用户指定的文件,然后允许用户从中查找某个单词所在的位置. 一个面向过程的落后的设计思想 将待检索文件以行为单位存放到Vector容器中,然后遍历容器,将容器内元素依次转存到字符串流对象中,然后在内层遍历这个字符串流对象,检索是否存在与给定单词匹配的单词.如果有则输出该行内容以及该行序号. 落后的原因及先进的设计思想 这是我以

【足迹C++primer】56、文本查询程序

/** * 功能:文本查询程序 * 时间:2014年7月23日10:26:09 * 作者:cutter_point */ #include<iostream> #include<algorithm> #include<memory> #include<set> #include<map> #include<fstream> #include<sstream> using namespace std; /* Alice Em

C++自学笔记_文本查询程序_《C++ Primer》

<C++ Primer> 第10章结束,用一个文本查询程序结束本章 :) 程序将读取用户指定的任意文本文件,然后允许用户从该文件中查找单词.查询的结果是该单词出现的次数,并列出每次出现所在的行.如果某单词在同一行 中多次出现,程序将只显示该行一次.行号按照升序显示. 程序支持以下任务: · 它必须允许用户指明要处理的文件的名字.程序将存储该文件的内容,以便输出每个单词所在的原始行. · 它必须将每一行分解为各个单词,并记录每个单词所在的行.在输出行号时,应保证以升序输出,并且不重复. · 对特