一、文本查询程序实现
书中题目:
我们将实现一个简单的文本查询程序,我们的程序允许用户在一个给定文件中查询单词。查询结果是单词在文件中出现的次数及其所在行的列表。如果一个单词在一行中出现多次,此行只列出一次。行会按照升序输出。我们可以直接使用vector 、set和map来直接编写文本查询程序,但我们在这里定义一个抽象的解决方案会更有效。
程序支持以下任务:
1.它必须允许用户指明要处理的文件的名字。程序将存储该文件的内容,以便输出每个单词所在的原始行。
2.它必须将每一行分解为各个单词,并记录每个单词所在的行。在输出行号时,应保证以升序输出,并且不重复。
3.对特定单词的查询将返回出现该单词的所有行的行号。
4.输出某单词所在的行文本时,程序必须能够根据给定的行号从输入文件中获取相应的行。
假定要查询的文件路径为:C:\Users\t\source\repos\vector\ConsoleApplication2\text.txt
text.txt:
wo ai wo de zhong guo
wo ai wo de xiao shu lan
Sunday's coming I wanna drive my car
这周日我想开着我的爱车
To your apartment with the present like a star
像明星一样带着的礼物去你的公寓
Forecaster said the weathers may be rainy hard
天气预报说天气糟透了
But I know the sun will shine for us
但是太阳会为我们闪耀
Oh lazy seagull fly me from the dark
喔~慵懒的海鸥引领我走向光明
I dress my jeans and feed my monkey banana
穿上我的牛仔,塞满钞票
Then I think my age how old,skyline how far
我想到,我有多大,地平线有多远
Or we need each other in California
喔~在加州我们需要彼此
二、代码:
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <fstream>
#include <sstream>
#include <stdexcept>
using namespace std;
class TextQuery {
public:
typedef vector<string>::size_type line_no;
void read_file(ifstream& is) {
store_file(is);
build_map();
}
set<line_no> run_query(const string&) const;
string text_line(line_no) const;
private:
void store_file(ifstream&);
void build_map();
vector<string> lines_of_text;//存放着txt文件
map<string, set<line_no> >word_map;//存放行号和内容
};
/*存储输入文件*/
void TextQuery::store_file(ifstream& is) {
string textline;
while (getline(is, textline)) {//其中 is 是正在读取的输入流,而 textline 是接收输入字符串的 string 变量的名称。
lines_of_text.push_back(textline);
}
}
/*建立map容器*/
void TextQuery::build_map() {
for (line_no line_num = 0; line_num != lines_of_text.size(); ++line_num) {//逐行
istringstream line(lines_of_text[line_num]);//把读入的每行分解为单词
string word;
while (line >> word) { //对每个单词
word_map[word].insert(line_num); // 插入map中
}
}
}
/*支持查询*/
set<TextQuery::line_no> TextQuery::run_query(const string& query_word) const {//查询str
map<string, set<line_no> >::const_iterator loc = word_map.find(query_word);//用find查找不会把单词添加到wordmap中
if (loc == word_map.end())
return set<line_no>();//没找到
else
return loc->second;//找到了,返回次数
}
/*run_query返回值的使用*/
string TextQuery::text_line(line_no line) const {
if (line < lines_of_text.size())
return lines_of_text[line];
else
throw out_of_range("line number out of range");
}
string make_plural(TextQuery::line_no ctr, const string& word, const string& ending) {
return (ctr == 1) ? word : word + ending;
}
void print_results(const set<TextQuery::line_no>& locs, const string& sought, const TextQuery& file) {
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size = locs.size();
cout << "\n" << sought << " occurs " << size << make_plural(size, " time", "s") << endl;
line_nums::const_iterator it = locs.begin();
for (; it != locs.end(); ++it) {
cout << "\t(in line " << (*it) + 1 << ") " << file.text_line(*it) << endl;//输出行号和内容
}
}
int main()
{
ifstream infile; //infile指向我们要处理的文件
cout << "输入查询文件放在哪里: ";
string fileName;
getline(cin, fileName);//获取输入的路径
infile.open(fileName.c_str());//以输入的方式打开文件
TextQuery tq; //实例化对象
tq.read_file(infile);//读取txt文件、建立map;
while (true) {
cout << endl << "输入要找的单词,或者输入 q 退出 : ";
string str;
cin >> str;//获取输入的单词
if (!cin || str == "q")//控制主函数循环:到了文件尾或 者输入q ;退出
break;
set<TextQuery::line_no> locs = tq.run_query(str);
print_results(locs, str, tq);//次数、cin字符、实例化对象tq;
}
return 0;
}
怕什么真理无穷,进一步有进一步的欢喜!