单词查询程序—《C++ primer 4》源代码详细注释

来源:互联网 发布:psv破解重构数据库 编辑:程序博客网 时间:2024/06/05 10:42

// 单词查询程序—《C++ primer 4》源代码详细注释,注释都是我的理解,错了也合理。

#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<sstream>
#include<fstream>
#include<set>
//#include<utility>

using namespace std;

// 打开文件流
ifstream& open_file(ifstream &in,const string &file)
{
 in.close();
 in.clear();
 in.open(file.c_str());
 return in;
}

// make_plural函数作用:若ctr大于1,则返回word+ending,否则返回word,如:实参为(2,"time","s"),则返回 times
string make_plural(size_t ctr,const string &word,const string &ending)
{
 return (ctr == 1) ? word : word + ending;
}

// 类定义
class TextQuery
{
public:
 typedef vector<string>::size_type line_no;   // 定义类型名
 void read_file(ifstream &is) // 该函数每次从文件中读取一行,并将它保存在vector容器中。输入完毕后,将创建关联每个单词及其所在行的map容器
 {
  store_file(is);     // 调用‘存储输入文件函数’
  build_map();  // 调用‘建立单词map容器函数’
 }
 set<line_no> run_query(const string &) const; // 定义‘查询单词函数’:返回的set对象包含形参string对象的所有行的行号
 string text_line(line_no) const;  // 返回输入文本中该行号对应的文本行
private:
 void store_file(ifstream &); // 将文件内容存储在vector容器中
 void build_map();    // 将每行分解为各个单词,创建map容器对象,同时记录每个单词出现的行号
 vector<string> lines_of_text;
 map<string,set<line_no>> word_map;
};

// 存储读入文件
void TextQuery::store_file(ifstream &is)
{
 string textline;
 while(getline(is,textline))  // 我们希望每次存储文件的一行内容,所以使用getline读取输入,每读一行就添加到vector容器中
  lines_of_text.push_back(textline);
}

// 建立单词map容器
void TextQuery::build_map()   // 该函数用到8.5节描述的istringstream,及用map写的单词统计程序
{
 for(line_no line_num = 0;line_num != lines_of_text.size();++line_num)
 {
  istringstream line(lines_of_text[line_num]);  // 将每行作为副本赋值给line
  string word;
  while(line >> word)  // while循环将对该行进行逐个单词处理(即将一行分解为各个单词)
   word_map[word].insert(line_num); // 用insert给该单词添加关联行号(该map容器的下标操作将返回set对象)
 }
}
 
// 支持查询   run_query
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>();  // 返回一个空set对象
 else
  return loc->second;  // 返回该单词的set对象(即存储了该单词所关联的行数)
}

// 还回值的使用
string TextQuery::text_line(line_no line) const
{
 if(line < lines_of_text.size())
  return lines_of_text[line];  // 返回该行号所对应的文本行
 throw out_of_range("line number out of range");
}

// 函数print_results     形参:被查询单词对应set对象的指针,被查询的单词,一个TextQuery类型对象的引用(即输入文本)
void print_results(const set<TextQuery::line_no>& locs,const string &sought,const TextQuery &file)
{
 typedef set<TextQuery::line_no> line_nums;  // 记录行号的set的简单使用
 line_nums::size_type size = locs.size(); // 对应单词所关联的行数(即出现次数)
 cout << "/n" << sought << " occurs " << size << " " << make_plural(size,"time","s") << endl;  // 输出:‘某单词’出现 N 次。(make_plural函数作用:若N大于1,则为times,否则为time)
 line_nums::const_iterator it = locs.begin(); // 指向该set对象的首元素指针
 for( ; it != locs.end(); ++it)
 {
  cout << "/t(line " << (*it) + 1 << ")" << file.text_line(*it) << endl; // 输出:(line 数字) 该行文字内容。
 }
}

// 主函数
int main(int argc,char **argv)
{
 ifstream infile;   // 声明文件流
 if(argc < 2 || !open_file(infile,argv[1]))  // 如果从控制台获取的字符串小于2  或  调用open_file()函数失败,就跑出异常结束程序
 {
  cerr << "No input file!" << endl;
  return EXIT_FAILURE;
 }
 TextQuery tq;     // 声明TextQuery对象
 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;
  set<TextQuery::line_no> locs = tq.run_query(s);  // 被查询单词所关联的行数
  print_results(locs,s,tq);  // 输出结果
 }
 return 0;
}

原创粉丝点击