现在的位置: 首页 > 综合 > 正文

C++Primer读书笔记(六)

2013年08月11日 ⁄ 综合 ⁄ 共 4816字 ⁄ 字号 评论关闭
C++Primer中一个简单的文本单词查询小程序
TextQuery头文件:
#ifndef TEXTQUERY_H
#define TEXTQUERY_H

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <cstring>
#include <cctype>
using namespace std;

class TextQuery
{
public:
    // typedef to make declarations easier
	TextQuery(void);
	virtual ~TextQuery(void);

	typedef string::size_type str_size;
	typedef vector<string>::size_type LineNo;

	/* 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 returns a requested line from the input file
     */
	void ReadFile(ifstream &is)
	      { StoreFile(is);BuildMap();}
	set<LineNo> RunQuery(const string&) const;
	string TextLine(LineNo) const;
	str_size size() const 
	           { return LinesText.size(); }
	void DisplayMap();        // debugging aid: print the map
private:
	// utility functions used by read_file
	void StoreFile(ifstream&);    //store input file
	void BuildMap();                 //associated each word with a set of line numbers
	vector<string> LinesText;   // remember the whole input file
	map<string, set<LineNo> > word_map;  // map word to set of the lines on which it occurs
	static string whitespace_chars;     
	// canonicalizes text: removes punctuation and makes everything lower case
	static string cleanup_str(const string&);
};

#endif

TextQuery源文件:

#include "TextQuery.h"
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
#include <stdexcept>
using namespace std;

TextQuery::TextQuery(void)
{
}

TextQuery::~TextQuery(void)
{
}

set<TextQuery::LineNo> TextQuery::RunQuery(const string &QueryWord) const
{
	// Note: must use find and not subscript the map directly
	// to avoid adding words to word_map!
	map<string, set<LineNo> >::const_iterator loc = word_map.find(QueryWord);
	if (loc == word_map.end())
	{
		return set<LineNo>(); // not found,return empty set
	}
	else
	{
		return loc->second;    //fetch and return set of line numbers for this word
	}
}
// read input file: store each line as element in LinesText
void TextQuery::StoreFile(ifstream &is)
{
	string textline;
	while (getline(is, textline))
	{
		LinesText.push_back(textline);
	}
}

// \v: vertical tab; \f: formfeed; \r: carriage return are
// treated as whitespace characters along with space, tab and newline
string TextQuery::whitespace_chars(" \t\n\v\r\f");

string TextQuery::TextLine(LineNo line) const
{
	if (line < LinesText.size())
	{
		return LinesText[line];
	}
	throw out_of_range("line number out of range");
}

// finds whitespace-separated words in the input vector
// and puts the word in word_map along with the line number
void TextQuery::BuildMap()
{
	// process each line from the input vector
	for (LineNo line_num = 0; line_num != LinesText.size(); ++line_num)
	{
		// we'll use line to read the text a word at a time
		istringstream line(LinesText[line_num]);
		string word;
		while (line>>word)
		{
			word_map[cleanup_str(word)].insert(line_num);  // add this line number to the set;
		}
	}
}

void TextQuery::DisplayMap()
{
	map< string, set<LineNo> >::iterator iter = word_map.begin(),
		iter_end = word_map.end();

	// for each word in the map
	for ( ; iter != iter_end; ++iter) {
		cout << "word: " << iter->first << " {";

		// fetch location vector as a const reference to avoid copying it
		const set<LineNo> &text_locs = iter->second;
		set<LineNo>::const_iterator loc_iter = text_locs.begin(),
			loc_iter_end = text_locs.end();

		// print all line numbers for this word
		while (loc_iter != loc_iter_end)
		{
			cout << *loc_iter;

			if (++loc_iter != loc_iter_end)
				cout << ", ";

		}

		cout << "}\n";  // end list of output this word
	}
	cout << endl;  // finished printing entire map
}

// lower-case to upper-case
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;
}

主程序:

#include <string>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <fstream>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include "TextQuery.h"
using namespace std;

//open file
ifstream& OpenFile(ifstream &in, const string &file)
{
	in.close();       //close in case it was already open
	in.clear();       //clear any existing errors
	in.open(file.c_str()); //open the file we were given
	return in;
}
//put words' odd or plural
string make_plural(size_t ctr, const string &word, const string &ending)
{
	return ( ctr == 1) ? word : (word+ending);
}
//print the Results
void PrintResults(const set<TextQuery::LineNo>& locs, 
				  const string &sought, const TextQuery &file)
{
	typedef set<TextQuery::LineNo> line_nums;
	line_nums::size_type size = locs.size();
	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)+1<<")"<<file.TextLine(*it)<<endl;
	}
}

int main(int argc, char *argv[])
{
	//open the from which user will query words
	ifstream infile;
	if (!OpenFile(infile, "tianqi.txt"))
	{
		cerr << "No input file!" << endl;
		return EXIT_FAILURE;
	}

	TextQuery tq;
	tq.ReadFile(infile);   //builds query map
	while (true)
	{
		cout<<"enter word to look for, or q to quit";
		string s;
		cin>>s;            //error:debbug  here will be stoped why????
		//stop if hit eof on input or a 'q'is entered
		if (!cin || s == "q")
		{
			break;
		}
		//get the set of line numbers on which this word appears
		set<TextQuery::LineNo>locs = tq.RunQuery(s);
		//print count and all occurences, if any
		PrintResults(locs, s, tq);
	}
	return 0;
}

这个程序还有一个调试错误!


【上篇】
【下篇】

抱歉!评论已关闭.