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


    需求

    程序读取用户指定的任意文本文件,允许用户从该文件中查找单词。查询结果是该单词出现的次数,并列出每次出现所在行,如果某单词在同一行中多次出现,程序将只显示该行一次。行号按升序显示,即第 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<<"	";
    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 }

    运行结果

     

    代码点此下载

  • 相关阅读:
    论文(卷积数据流)-Communication Lower Bound in Convolution Accelerators
    CPU架构相关
    Verilog-数据包检测器
    多比特乘法器的分解
    Verilog-数字时钟无毛刺切换
    Booth乘法器
    C++:地平线2019相关题
    C++:char数组和string类
    C++:strcpy函数
    半导体 semiconductor 相关知识
  • 原文地址:https://www.cnblogs.com/raichen/p/4900308.html
Copyright © 2020-2023  润新知