C++primer练习12.27-12.32
练习12.27
TextQuery和QueryResult类只使用了我们已经介绍过的语言和标准库特性。
main.cpp
#include<iostream> #include <string> #include <vector> #include <fstream> #include "QueryResult.h" #include "TextQuery.h" using std::ostream; using std::cout; using std::endl; using std::cin; ostream &print(ostream & os, const QueryResult &qr) { // if the word was found, print the count and all occurrences os << qr.sword << " occurs " << qr.lines->size() << " " << make_plural(qr.lines->size(), "time", "s") << endl; // print each line in which the word appeared // for every element in the set for (set<TextQuery::line_no>::const_iterator num = qr.lines->begin(); num != qr.lines->end(); ++num) // don't confound the user with text lines starting at 0 os << "\t(line " << *num + 1 << ") " << *(qr.paragraph->begin() + *num) << endl; return os; } void runQueries(std::ifstream&infile) { TextQuery tq(infile); while(true) { cout<<"enter word to look for ,or to quit: "; string s; if(!(cin>>s)||s=="q")break; print(cout,tq.query(s)); } } int main() { ifstream in("number.txt"); runQueries(in); }
TextQuery.h
#ifndef TEXTQUERY #define TEXTQUERY #include <memory> #include <string> #include <vector> #include <iostream> #include <map> #include <fstream> #include <sstream> #include "QueryResult.h" #include <set> using std::string; using std::vector; using std::map; using std::ifstream; using std::set; using std::shared_ptr; class TextQuery{ public : typedef vector<string>::size_type line_no; typedef shared_ptr<set<line_no>> linetype; friend class QueryResult; shared_ptr<vector<string>> text; map<string,shared_ptr<set<line_no>>> record; TextQuery(ifstream &f); QueryResult query(const string& s); string cleanup_str(const string &word); private : }; string TextQuery::cleanup_str(const string &word) { string ret; for (string::const_iterator it = word.begin(); it != word.end(); ++it) { if (!ispunct(*it)) ret += tolower(*it); } return ret; } using std::stringstream; TextQuery::TextQuery(ifstream &f):text(new vector<string>) { string s; while(getline(f,s)) { text->push_back(s); int n = text->size() - 1; string word; std::istringstream eword(s); while(eword>>word) { word=cleanup_str(word); linetype &lines = record[word]; if (!lines) lines.reset(new set<line_no>); lines->insert(n); }} } QueryResult TextQuery::query(const string &s) { static linetype nodata; map<string,shared_ptr<set<line_no>>>::const_iterator pos=record.find(s); if (pos == record.end()) return QueryResult(s, nodata, text); // not found else return QueryResult(s, pos->second, text); } string make_plural (size_t ctr, const string& word, const string& ending) { return (ctr>1)?word+ending:word; } #endif
QueryResult.h
#ifndef QUERYRESULT #define QUERYRESULT #include <string> #include <vector> #include <stdlib.h> #include <map> #include <set> #include <memory> using std::string; using std::vector; using std::map; using std::set; using std::shared_ptr; class TextQuery; class QueryResult{ public: typedef vector<string>::size_type line_no; friend class TextQuery; QueryResult(string s,shared_ptr<set<line_no>> p,shared_ptr<vector<string>> text):sword(s),lines(p),paragraph(text){} string sword; shared_ptr<set<line_no>> lines; shared_ptr<vector<string>> paragraph; private: }; #endif
print函数和TextQuery的构造抄了书上的,但原来自己码的没问题,只是在打开file的txt码成text,搞得程序一直崩,我就直接抄了,后来还是崩,一行行看才发现哭死
练习12.28
编写程序实现文本查询,不使用类,用标准库容器
#include <sstream> #include <fstream> #include <iostream> #include <vector> #include <string> #include <map> #include <set> #include <ctype.h> #include <memory> using std::map; using std::set; using std::string; using std::vector; using std::ifstream; using std::ostream; using std::shared_ptr; using std::cout; using std::endl; using line_no=vector<string>::size_type; map<string,set<line_no>> lines; vector<string> file; string cleanup_str(string s) { string ret; for(string::const_iterator it=s.begin();it!=s.end();++it) { if(!ispunct(*it)) ret+=tolower(*it); } return ret; } void storage(ifstream& f) { string line; while(getline(f,line)) { file.push_back(line); int n=file.size(); std::istringstream eword(line); string word; while(eword>>word) { word=cleanup_str(word); lines[word].insert(n); } } } void search(const string&s) { cout<<s<<" occurs "; if(&lines[s]){ cout<<lines[s].size()<<" times "<<endl; for(auto d:lines[s]) cout<<"\t(line : "<<d<<" "<<file[d-1]<<endl; } else cout<<" 0 "<<" time "<<endl; } int main() { ifstream in("number.txt"); storage(in); while(true) { cout<<"enter word to look for ,or q to quit : "<<endl; string s; if(!(std::cin>>s)||s=="q")break; search(s); } return 0; }
练习12.29
我们曾经用do while循环来编写管理用户交互的循环。用do while重写本节程序。解释你倾向哪个版本
#include <sstream> #include <fstream> #include <iostream> #include <vector> #include <string> #include <map> #include <set> #include <ctype.h> #include <memory> using std::map; using std::set; using std::string; using std::vector; using std::ifstream; using std::ostream; using std::shared_ptr; using std::cout; using std::endl; using line_no=vector<string>::size_type; map<string,set<line_no>> lines; vector<string> file; string cleanup_str(string s) { string ret; for(string::const_iterator it=s.begin();it!=s.end();++it) { if(!ispunct(*it)) ret+=tolower(*it); } return ret; } void storage(ifstream& f) { string line; while(getline(f,line)) { file.push_back(line); int n=file.size(); std::istringstream eword(line); string word; while(eword>>word) { word=cleanup_str(word); lines[word].insert(n); } } } void search(const string&s) { cout<<s<<" occurs "; if(&lines[s]){ cout<<lines[s].size()<<" times "<<endl; for(auto d:lines[s]) cout<<"\t(line : "<<d<<" "<<file[d-1]<<endl; } else cout<<" 0 "<<" time "<<endl; } int main() { ifstream in("number.txt"); storage(in); do { cout<<"enter word to look for ,or q to quit : "<<endl; string s; if(!(std::cin>>s)||s=="q")break; search(s); }while(true); return 0; }
用类更方便在大型程序里处理数据,也便于后续改善,用vector等容器,逻辑偏过程,不易于开发大程序,不过写短片代码倒挺上手,受了c的影响,还是得习惯用用类
练习12.30
定义你自己版本的TextQuery和QueryResult类
::如12.27
练习12.31
如果用vector代替set保存行号,会有什么差别?哪种方法更好?为什么?
::set防止重复,避免同一行出现而重复记录
练习12.32
重写TextQuery和QueryResult类,用StrBlob代替vector<string>保存输入文件
class QueryResult{ public: typedef vector<string>::size_type line_no; friend class TextQuery; QueryResult(string s,shared_ptr<set<line_no>> p,shared_ptr<vector<string>> text):sword(s),lines(p),paragraph(text){} string sword; shared_ptr<set<line_no>> lines; shared_ptr<StrBlob> paragraph; private: };
class TextQuery{ public : typedef vector<string>::size_type line_no; typedef shared_ptr<set<line_no>> linetype; friend class QueryResult; friend class StrBlob; shared_ptr<StrBlob> text; map<string,shared_ptr<set<line_no>>> record; TextQuery(ifstream &f); QueryResult query(const string& s); string cleanup_str(const string &word); private : };