在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
[0. 需求] 最近在粗略学习《C++ Primer 4th》的容器内容,关联容器的章节末尾有个很不错的实例。 程序将读取用户指定的任意文本文件,然后允许用户从该文件中查找单词。 本人用到的文本文件“ inputfile.txt ”,内容如下(显示的行号并非文件原内容): 1 Our program will read a file specified by the user and then allow the user to 2 search the file for words that might occur in it. The result of a query will be 3 the number of times the word occurs and a list of lines on which 4 it appears. If a word occurs more than once on the same line, 5 our program should be smart enough to display that line only once. 6 Lines should be displayed in ascending orderthat is, 7 line 7 should be displayed before line 9, and so on. [1. 程序的设计] 设计程序的一个良好习惯是首先将程序所涉及的操作列出来。 本程序的需求如下: 1.1 数据结构 我们将用一个简单的类 TextQuery ,再配合几种容器的使用,实现这个程序的要求。 综上所述,我们定义的 TextQuery 类将有两个数据成员: 1.2 操作 对于类还要求有良好的接口。 类的接口需提供下列三个 public 函数: 2. run_query 成员函数,其形参为一个 string 类型对象,返回一个 set 对象, 3. text_line 成员函数,其形参为一个行号,返回输入文本中该行号对应的文本行。 4. store_file 函数读入文件,并将文件内容存储在 vector 容器对象中。 5. build_map 函数将每一行分解为各个单词,创建 map 容器对象,同时记录每个单词出现的行号。 [2. TextQuery 类] 定义 TextQuery 类的头文件 “ TextQuery.h ” 内容如下: #ifndef __TEXTQUERY_H__ #define __TEXTQUERY_H__ #include <iostream> #include <istream> #include <fstream> #include <vector> #include <map> #include <set> #include <utility> #include <string> typedef std::vector<std::string>::size_type line_no; class TextQuery { public: // interface: void read_file(std::ifstream &is) { store_file(is); build_map(); } std::set<line_no> 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&); void build_map(); // associate each word with a set of line numbers // remember the whole input file std::vector<std::string> lines_of_text; // map word to set of the lines on which it occurs std::map< std::string, std::set<line_no> > word_map; }; #endif 注意:这个类的定义中,在引用标准库内容时都必须完整地使用 std:: 限定符。 read_file 函数在类的内部定义。该函数首先调用 store_file 读取并保存输入文件, [3. TextQuery 类的使用] 下面的主程序 main 使用 TextQuery 对象实现简单的用户查询会话。 3.1 引子 程序首先检查 argv[1] 是否合法,然后调用 open_file 函数打开以 main 函数实参形式给出的文件。 open_file 函数的实现如下: // opens in binding it to the given file ifstream& open_file(ifstream &in, const string &file) { in.close(); // close in case it was already open in.clear(); // clear any existing errors // if the open fails, the stream will be in an invalid state in.open(file.c_str()); // open the file we were given return in; // condition state is good if open succeeded } 3.2 实现查询 为了使用户在每次会话时都能查询多个单词,我们将提示语句也置于 while 循环中: #include "TextQuery.h" define EXIT_FAILURE -1 using namespace std; int main(int argc, char *argv[]) { // open the file from which user will quer words ifstream infile; if(argc < 2 || !open_file(infile, argv[1])){ cerr << "No input file!" << endl; return EXIT_FAILURE; } TextQuery tq; tq.read_file(infile); // prompt for a word to file and print result while(true){ cout << "Enter word to look for(or Q/q to Quit): \n" ; string str; cin >> str; // stop if hit eof on input or a 'Q' is entered if(!cin || str == "Q" || str == "q") break; // get tje set of line numbers on which this word appears set<line_no> locs = tq.run_query(str); // print count an all occurrences, if any print_results(locs, str, tq); } return 0; } while 循环条件为布尔字面值 true,这就意味着循环条件总是成立。 3.3 输出结果 输出时,首先给出查询到的匹配个数,即 set 对象的大小。 // return plural version of word if ctr isn't 1 string make_plural(size_t ctr, const string &word, const string &ending) { return (ctr == 1) ? word : word + ending; } void print_results(const set<line_no>& locs, const string& sought, const TextQuery& file) { // if the word was found, then print count and all occurrences typedef set<line_no> line_nums; line_nums::size_type size = locs.size(); cout << "\n" << sought << " occurs " << size << " " << make_plural(size, "time", "s") << endl; // print each line in which the word appeared line_nums::const_iterator it = locs.begin(); for(; it != locs.end(); ++it){ // don't confound user with text lines starting at 0 cout << "\t(line" << (*it) +1 << ")" << file.text_line(*it) << endl; } }
以上几个函数定义和实现都放在 main.cpp 文件之中。 注意:为了与 C++ 的容器和数组下标编号匹配,在储存文本时,我们以行号 0 存储第一行。 [4. 成员方法的实现] TextQuery 类的成员方法实现 “ TextQuery.cpp” 文件内容如下: #include "TextQuery.h" #include <stdexcept> #include <sstream> using namespace std; set<line_no> TextQuery::run_query(const string &query_word) const { // must use find and not subscript he map directly // to avoid adding words to word_map map< string, set<line_no> >::const_iterator loc = word_map.find(query_word); if(loc == word_map.end()){ // not found, return empty set return set<line_no>(); } else{ // fectch and return set of line numbers for this word return loc->second; } } 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"); } // utility functions used by read_file void TextQuery::store_file(ifstream &is) { string textline; while (getline(is, textline)) lines_of_text.push_back(textline); } // associate each word with a set of line numbers void TextQuery::build_map() { // process each line from the input vector for (line_no line_num = 0; line_num != lines_of_text.size(); ++line_num) { // we'll use line to read the text a word at a time istringstream line(lines_of_text[line_num]); string word; while (line >> word){ // add this line number to the set; // subscript will add word to the map if it's not already there word_map[word].insert(line_num); } } } [5. 编译运行] 之前一直是用 CFree5.0 做的《C++ Primer 4th》的练习, 编译成功后,文件如下: 运行,命令如下: 结果显示如下: 根据运行结果观察,应该是实现了预期的程序功能。O(∩_∩)O 哈哈~ |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论