容器的综合应用:文本查询程序

需求

程序读取用户指定的任意文本文件,允许用户从该文件中查找单词。查询结果是该单词出现的次数,并列出每次出现所在行,如果某单词在同一行中多次出现,程序将只显示该行一次。行号按升序显示,即第 7 行应该在第 9 行之前输出,依此类推。例如,以本章的内容作为文件输入,然后查找单词“element”。输出的前几行应为:

element occurs 125 times
(line 62) element with a given key.
(line 64) second element with the same key.
(line 153) element |==| operator.
(line 250) the element type.
(line 398) corresponding element.
后面省略了大约 120 行。

看着书上的例子,自己写了下,大致思路是

读取文件,将文件以行为单位,放入vector<string>,再遍历vector<string>,将每行每个单词读入map< string,set<unsigned> >中,最后从map中查找读取

注意的地方

程序是不区分大小写的,还需要去掉文章中的标点需要调用函数

头文件#include<cctype>

ispunct() 检查是否是非空格、非数字和非英文字母,类似函数isspace,isdigit,isalpha

tolower() 把字符转换成小写字母

对const成员的迭代器需要用const_iterator

对于内置类型,和长度比较短(8字节以内)的浅层结构,类等对象,传值比传引用效率更高。

对超过8字节的对象,一般传引用效率更高。

但实际上传引用或传值的选择,主要取决于功能需求而非效率需求。

详解

获取文件对象:

1 ifstream& open_file(ifstream &in,const string &file)
2 {
3     in.close();
4     in.clear();
5     in.open(file.c_str());
6     return in;
7 }

读文件,创建vector和map

 1 void TextQuery::read_file(ifstream &in)
 2 {
 3     store_file(in);
 4     build_map();
 5 }
 6
 7 void TextQuery::store_file(ifstream &in)
 8 {
 9     string textline;
10     while(getline(in,textline))
11         lines_of_text.push_back(textline);
12 }
13
14 void TextQuery::build_map()
15 {
16     for(line_no line_num = 0;line_num != lines_of_text.size();line_num++)
17     {
18         istringstream line(lines_of_text[line_num]);
19         string word;
20         while(line >> word)
21         {
22             word = cleanup_str(word);
23             word_map[word].insert(line_num);
24         }
25
26     }
27 }

处理单词中的符号,忽略大小写

 1 string TextQuery::cleanup_str(const string &word)
 2 {
 3     string ret;
 4     for(string::const_iterator it = word.begin();it != word.end();++it)
 5     {
 6         if(!ispunct(*it))
 7             ret += tolower(*it);
 8     }
 9     return ret;
10 }

查找单词,返回值是map的第二个元素set,用来保存单词所在的行号

1 set<TextQuery::line_no> TextQuery::run_query(const string &query_word) const
2 {
3     map< string,set<line_no> >::const_iterator loc = word_map.find(query_word);
4     if( loc == word_map.end() )
5         return set<line_no>();    //找不到返回空的set对象
6     else
7         return loc ->second;
8 }

返回查找结果,这里有个漏洞,查找单词的数目是为单词所出现的行数(因为set不存储重复元素)

void TextQuery::print_result(set<line_no> locs,const string &query_word)
{
    cout<<query_word<<":"<<locs.size()<<endl;
    set<line_no>::iterator it = locs.begin();
    while(it != locs.end())
    {
        cout<<"(line "<<*it+1<<") ";
        cout<<lines_of_text[*it]<<endl;
        it++;
    }
}

写了两个辅助函数,并未调用,为了查看vector和map中的内容

 1 void TextQuery::show_vec()
 2 {
 3     vector<string>::iterator ite = lines_of_text.begin();
 4     while(ite != lines_of_text.end())
 5         cout<<*ite++<<endl;
 6 }
 7 void TextQuery::show_map()
 8 {
 9     map< string,set<line_no> >::iterator loc = word_map.begin();
10     while(loc != word_map.end())
11     {
12         cout<<loc->first<<"\t";
13         set<line_no>::iterator it = (loc->second).begin();
14         while(it != (loc->second).end())
15         {
16             cout<<*it + 1<<" ";
17             it++;
18         }
19         cout<<endl;
20         loc++;
21     }
22 }

运行结果

代码点此下载

时间: 2024-10-26 00:42:35

容器的综合应用:文本查询程序的相关文章

C++ Primer 学习笔记_38_STL实践与分析(12)--容器的综合应用:文本查询程序

STL 实践与分析 -- 容器的综合应用:文本查询程序 引言: 本章中最重点的实例,因为不需要用到 multiset 与 multimap 的内容,于是将这一小节提到了前面,通过这个实例程序,大师分析问题的智慧,大师的编程风格,大师对程序的控制能力,由此可见一斑.因此,我对这一小节的内容几乎不做修改,或只做很小的更改(因为有些东西不同人有不同的理解),搬出来,以供大家仔细品读. 要求: 我们的程序将读取用户指定的 任意文本文件 , 然后允许用户从该文件中查找单词. 查询的结果是该单词出现的次数 

第十四篇:一个文本查询程序的实现

前言 本文将讲解一个经典的文本查询程序,对前面所学的容器相关知识进行一个从理论到实际的升华,同时也对即将学习的面向对象知识来一次初体验. 程序描述 要求实现这样一个程序:读取用户指定的文件,然后允许用户从中查找某个单词所在的位置. 一个面向过程的落后的设计思想 将待检索文件以行为单位存放到Vector容器中,然后遍历容器,将容器内元素依次转存到字符串流对象中,然后在内层遍历这个字符串流对象,检索是否存在与给定单词匹配的单词.如果有则输出该行内容以及该行序号. 落后的原因及先进的设计思想 这是我以

【足迹C++primer】56、文本查询程序

/** * 功能:文本查询程序 * 时间:2014年7月23日10:26:09 * 作者:cutter_point */ #include<iostream> #include<algorithm> #include<memory> #include<set> #include<map> #include<fstream> #include<sstream> using namespace std; /* Alice Em

C++自学笔记_文本查询程序_《C++ Primer》

<C++ Primer> 第10章结束,用一个文本查询程序结束本章 :) 程序将读取用户指定的任意文本文件,然后允许用户从该文件中查找单词.查询的结果是该单词出现的次数,并列出每次出现所在的行.如果某单词在同一行 中多次出现,程序将只显示该行一次.行号按照升序显示. 程序支持以下任务: · 它必须允许用户指明要处理的文件的名字.程序将存储该文件的内容,以便输出每个单词所在的原始行. · 它必须将每一行分解为各个单词,并记录每个单词所在的行.在输出行号时,应保证以升序输出,并且不重复. · 对特

文本查询程序

我们实现一个简单的文本查询程序.我们的程序允许用户在一个给定文件中查询单词,查询结果是单词在文件中出现的次数及所在行的列表.如果一个单词在一行中出现多次,此行只列出一次. #include<iostream> #include<map> #include<set> #include<string> #include<vector> #include<fstream> #include<sstream> #include&l

【足迹C++primer】41、文本查询程序

/** * 功能:使用标准库:文本查询程序 * 时间:2014年7月10日09:10:15 * 作者:cutter_point */ #include<iostream> #include<map> #include<set> #include<fstream> #include<sstream> #include<string> #include<vector> #include<memory> using

使用标准库:文本查询程序

使用标准库:文本查询程序 class QueryResult { friend std::ostream& print(std::ostream&,cost QueryResult&); public: Queryresult(std::string s, std::shared_ptr<std::set<line_no>> p, std::shared_ptr<std::vector<std::string>>f): sought(

C++ Primer第四版 15.9 再谈文本查询 程序实现

编程过程中发现书本中的示例程序并不完全,某些地方存在错误,现已改正并添加少许注释.. 1 #include<iostream> 2 #include<fstream> 3 #include<sstream> 4 #include<vector> 5 #include<map> 6 #include<set> 7 #include<algorithm> 8 #include<stdexcept> 9 using

&lt;&lt;c++ primer&gt;&gt;文本查询程序

#ifndef _TEXTQUERY_H #define _TEXTQUERY_H #include <vector> #include <string> #include <set> #include <map> #include <fstream> #include <sstream> class TextQuery { public: typedef std::vector<std::string>::size_ty