Text query Program-from C ++ Primer

Source: Internet
Author: User

This article summarizes and excerpts a text query program, a big example in C ++ primer. The main purpose is to learn the programming specifications of masters.


Program Requirements: read any text file specified by the user, and then allow the user to find words from the file. The query result shows the number of times a word appears and lists the rows that appear each time. If a word appears multiple times in the same row, the program displays the row only once and the row number is displayed in ascending order.

Analysis:

  1. Enter the file name;
  2. A row must be taken as a whole and output by the row number;
  3. Each row must be broken down into individual words, and the row where the word is located is recorded. All rows are returned for the word query;
  4. This section mainly describes the use of containers;

Solution:

  1. Use Vector to store the entire row. One element in the vector is a row;
  2. MAP is used to take words as keywords and the set of rows as satellite data;

The following is the included header file:

#include<utility>#include<set>#include<map>#include<vector>#include<string>#include<iostream>#include<fstream>#include<sstream>using namespace std;

Below are the main types of textquery:

class TextQuery { public: //typedef to make declarations easier typedef  std::vector<std::string>::size_type  line_no; typedef std::set<line_no>::const_iterator  set_it; /* interface:  * read_file() builds internal data structures  for the given file  * run_query() finds the given word and returns "set" of lines on which it appears  * text_line()  return a requested line from the input file  */ void read_file(std::ifstream&  is)                {  store_file(is);  build_map();}  std::pair<set_it,set_it>  run_query(const std::string& )  const;  std::string text_line(line_no) const; private: //utility functions used by read_file() void store_file(std::ifstream& );  //store input file void build_map();  //associated each word with a set of line numbers; std::vector<std::string> lines_of_text;  //remember the whole input file std::map<std::string, std::set<line_no> > word_map;  };

The following are the auxiliary functions make_plural and open_file:

/* This function provides a counter, a word and a word Terminator ending. When the counter value is greater than 1, return the plural version of the word */STD: String make_plural (size_t CTR, const STD: string & Word, const STD: string & ending) {return (CTR = 1 )? Word: Word + ending;} // open the given file STD: ifstream & open_file (STD: ifstream & in, const STD: string & file) {In. close (); // close in case it was already open in. clear (); // clear any existing errors; In. open (file. c_str (); Return in ;}

The following is the implementation of various functions in the class. Here, the implementation of run_query adopts the author's second suggestion and returns a pair of iterators:

// Step 1: store the input file void textquery: store_file (ifstream & IS) {string textline; while (Getline (is, textline) lines_of_text.push_back (textline );} // Step 2: Create the word map container void textquery: build_map () {for (line_no line_num = 0; line_num! = Lines_of_text.size (); ++ line_num) {istringstream line (lines_of_text [line_num]); string word; while (line> word) {// Add this line number to the Set; // word_map [word] is a set, and then insert word_map [word]. insert (line_num) ;}}// Step 3: Query/return a pair of set iterators pair <textquery: set_it, textquery: set_it> textquery :: run_query (const string & query_word) const {// You must note that you cannot directly query using subscript operations to prevent the insertion of nonexistent map elements <string, set <line_no>: c Onst_iterator loc = word_map.find (query_word); Return make_pair (loc-> second ). begin (), (loc-> second ). end () ;}// Step 4: output result void print_results (pair <textquery: set_it, textquery: set_it> & Its, const string & sought, const textquery & file) {typedef set <textquery: line_no> line_nums; line_nums: size_type size = 0; For (textquery: set_it beg = its. first; beg! = Its. second; ++ beg) ++ size; cout <"\ n" <sought <"occurs" <size <"" <make_plural (size, "time", "S") <Endl; line_nums: const_iterator it = its. first; For (; it! = Its. second; ++ it) {cout <"\ t (line" <(* It) + 1 <")" <file. text_line (* It) <Endl ;}} 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 ");}

The test procedure is as follows:

int main() { ifstream infile;     string filename; if(!(cin>>filename) || !open_file(infile,filename)){ cerr<<"NO input file!"<<endl; return EXIT_FAILURE; } TextQuery tq; tq.read_file(infile); while(true){ cout<<"enter word to look for, or q to quit: "; string s;cin>>s; if(!cin || s=="q") break; pair<TextQuery::set_it,TextQuery::set_it> its=tq.run_query(s); print_results(its,s,tq); }return 0;  }

Expand the preceding text query program. Requirements:

  1. Search for a single word and display all rows containing the word in ascending order;
  2. Non-query, use ~ Operator to display all unmatched rows;
  3. "Or" query, use the | Operator to display all rows that match any of the two query conditions;
  4. For "and" queries, use the & operator to display all rows that match both query conditions;
  5. Can combine these operators;

The design category is as follows:

When we use:

Query q = query ("") & query ("") | query ()

This usage tells us that user-level code cannot directly use our inheritance hierarchy. We can only define a handle class named query to hide the inheritance hierarchy. The user code is executed according to the handle. The user code can only indirectly manipulate the query_base object.

Take query q = query ("fiery") & query ("bird") | query ("wind") as an example:

Generate 10 objects: 5 query_base objects and their associated handles.

The code in the book is directly intercepted here:

 // private, abstract class acts as a base class for concrete query types     class Query_base {         friend class Query;     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 = 0;         // display prints the query         virtual std::ostream&             display(std::ostream& = std::cout) const = 0;     };

Query handle class:

// handle class to manage the Query_base inheritance hierarchy     class Query {         // these operators need access to the Query_base* constructor         friend Query operator~(const Query &);         friend Query operator|(const Query&, const Query&);         friend Query operator&(const Query&, const Query&);     public:         Query(const std::string&); // builds a new WordQuery         // copy control to manage pointers and use counting         Query(const Query &c): q(c.q), use(c.use) { ++*use; }         ~Query() { decr_use(); }         Query& operator=(const Query&);     // interface functions: will call corresponding Query_base operations     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(1)) { }         Query_base *q;         std::size_t *use;         void decr_use()         { if (--*use == 0) { delete q; delete use; } }     };

Overload OPERATOR:

 inline Query operator&(const Query &lhs, const Query &rhs)     {         return new AndQuery(lhs, rhs);     }     inline Query operator|(const Query &lhs, const Query &rhs)     {          return new OrQuery(lhs, rhs);     }     inline Query operator~(const Query &oper)     {         return new NotQuery(oper);     }

Output OPERATOR:

inline std::ostream&     operator<<(std::ostream &os, const Query &q)     {         return q.display(os);     }

Wordquery class:

class WordQuery: public Query_base {         friend class Query; // Query uses the WordQuery constructor         WordQuery(const std::string &s): query_word(s) { }         // concrete class: WordQuery defines all inherited pure virtual functions         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; // word for which to search      };

Notquery class:

class NotQuery: public Query_base {         friend Query operator~(const Query &);         NotQuery(Query q): query(q) { }          // concrete class: NotQuery defines all inherited pure virtual functions          std::set<line_no> eval(const TextQuery&) const;          std::ostream& display(std::ostream &os) const                { return os << "~(" << query << ")"; }          const Query query;     }; set<TextQuery::line_no>     NotQuery::eval(const TextQuery& file) const     {          // virtual call through the Query handle to eval          set<TextQuery::line_no> has_val = query.eval(file);          set<line_no> ret_lines;          // for each line in the input file, check whether that line is in has_val         // if not, add that line number to ret_lines         for (TextQuery::line_no n = 0; n != file.size(); ++n)             if (has_val.find(n) == has_val.end())                 ret_lines.insert(n);         return ret_lines;     }

Binary pure virtual class:

 class BinaryQuery: public Query_base {     protected:         BinaryQuery(Query left, Query right, std::string op):               lhs(left), rhs(right), oper(op) { }         // abstract class: BinaryQuery doesn't define eval         std::ostream& display(std::ostream &os) const         { return os << "(" << lhs << " " << oper << " "                                  << rhs << ")"; }         const Query lhs, rhs; // right- and left-hand operands         const std::string oper; // name of the operator      };

Orquery class:

class OrQuery: public BinaryQuery   {             friend Query operator|(const Query&, const Query&);             OrQuery(Query left, Query right):                         BinaryQuery(left, right, "|") { }             // concrete class: OrQuery inherits display and defines remaining pure virtual             std::set<line_no> eval(const TextQuery&) const;     };   set<TextQuery::line_no>     OrQuery::eval(const TextQuery& file) const     {             // virtual calls through the Query handle to get result sets for the operands             set<line_no> right = rhs.eval(file),                         ret_lines = lhs.eval(file); // destination to hold results             // inserts the lines from right that aren't already in ret_lines             ret_lines.insert(right.begin(), right.end());             return ret_lines;     }

Andquery class:

 class AndQuery: public BinaryQuery {         friend Query operator&(const Query&, const Query&);         AndQuery (Query left, Query right):                               BinaryQuery(left, right, "&") { }         // concrete class: And Query inherits display and defines remaining pure virtual         std::set<line_no> eval(const TextQuery&) const;     };    set<TextQuery::line_no>     AndQuery::eval(const TextQuery& file) const     {          // virtual calls through the Query handle to get result sets for the operands          set<line_no> left = lhs.eval(file),                             right = rhs.eval(file);          set<line_no> ret_lines; // destination to hold results          // writes intersection of two ranges to a destination iterator          // destination iterator in this call adds elements to ret          set_intersection(left.begin(), left.end(),                        right.begin(), right.end(),                        inserter(ret_lines, ret_lines.begin()));          return ret_lines;     }


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.