码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-10-25 22:31:41      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:

需求

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

运行结果

 技术分享

代码点此下载

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

标签:

原文地址:http://www.cnblogs.com/raichen/p/4900308.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!