textquery.h:
#include <string>
#include <vector>
#include <map>
#include <set>
class TextQuery
{
public:
typedef std::vector<std::string>::size_type line_no;
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:
void store_file(std::ifstream &);
void build_map();
std::vector<std::string> lines_of_text;
std::map<std::string, std::set<line_no> > word_map;
};
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <stdexcept>
#include "textquery.h"
void TextQuery::store_file(std::ifstream &is)
{
std::string textline;
while (getline(is, textline))
{
lines_of_text.push_back(textline);
}
}
void TextQuery::build_map()
{
for (line_no line_num = 0; line_num != lines_of_text.size(); ++line_num)
{
std::istringstream line(lines_of_text[line_num]);
std::string word;
while (line >> word)
{
word_map[word].insert(line_num);
}
}
}
std::set<TextQuery::line_no> TextQuery::run_query(const std::string &query_word) const
{
std::map<std::string, std::set<line_no> >::const_iterator loc = word_map.find(query_word);
if (loc == word_map.end())
{
return std::set<line_no>();
}
else
{
return loc->second;
}
}
std::string TextQuery::text_line(line_no line) const
{
if (line < lines_of_text.size())
{
return lines_of_text[line];
}
else
{
throw std::out_of_range("line number out of range");
}
}
main.cpp:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
#include <stdexcept>
#include "textquery.h"
using namespace std;
string make_plural(size_t ctr, const string &word, const string &ending)
{
return (1 == ctr) ? word : (word + ending);
}
ifstream & open_file(ifstream &in, const string &file)
{
in.close();
in.clear();
in.open(file.c_str());
return in;
}
void print_results(const set<TextQuery::line_no> &locs, const string &s, const TextQuery &file)
{
typedef set<TextQuery::line_no> line_nums;
line_nums::size_type size = locs.size();
cout << "\n" << s << " occurs " << size << make_plural(size, "time", "s") << endl;
line_nums::const_iterator it = locs.begin();
for (; it != locs.end(); ++it)
{
cout << "\t(line " << (*it + 1) << ") " << file.text_line(*it) << endl;
}
}
int main(int argc, char* argv[])
{
ifstream infile;
if ((argc < 2) || !open_file(infile, argv[1]))
{
cerr << "No input file!" << endl;
cout << "Usage: mmgrep <filename>" << endl;
return -1;
}
TextQuery tq;
tq.read_file(infile);
while (true)
{
cout << "Enter word to look for, or q to quit: ";
string s;
cin >> s;
if (!cin || s == "q")
{
break;
}
set<TextQuery::line_no> locs = tq.run_query(s);
print_results(locs, s, tq);
}
return 0;
}
makefile:
mmgrep: *.cpp
g++ -g *.cpp -o mmgrep
clean:
rm -f mmgrep
rm -f *.o
运行效果:
[textquery]$ ./mmgrep vimtutor
Enter word to look for, or q to quit: move
move occurs 31times
(line 22) the j key enough times to move the cursor so that Lesson 1.1
(line 28) ** To move the cursor, press the h,j,k,l keys as indicated. **
(line 37) Now you know how to move to the next lesson.
(line 39) 3. Using the down key, move to Lesson 1.2.
(line 45) move around much faster, once you get used to it. Really!
(line 78) 2. To fix the errors, move the cursor until it is on top of the
(line 101) 2. To make the first line the same as the second, move the cursor on top
(line 112) 5. When you are comfortable inserting text move to lesson 1.5.
(line 137) 5. When you are comfortable appending text move to lesson 1.6.
(line 157) 5. If you have quit vimtutor in step 1 restart the vimtutor and move down to
(line 252) move the cursor as specified.
(line 262) 2. Type 2w to move the cursor two words forward.
(line 264) 3. Type 3e to move the cursor to the end of the third word forward.
(line 266) 4. Type 0 (zero) to move to the start of the line.
(line 270) ---> This is just a line with words you can move around in.
(line 311) 3. Now move to the fourth line.
(line 341) 8. These are very useful commands. Now move on to the Lesson 2 Summary.
(line 363) 6. To move to the start of the line use a zero: 0
(line 409) 5. Now move on to Lesson 3.3.
(line 427) 4. Press <ESC> and move to the next character that needs to be changed.
(line 488) Type G to move to a line in the file. **
(line 499) 2. Press G to move you to the bottom of the file.
(line 500) Type gg to move you to the start of the file.
(line 540) 3. The cursor will move to the matching parenthesis or bracket.
(line 542) 4. Type % to move the cursor to the other matching bracket.
(line 653) 2. Press v and move the cursor to the fifth item below. Notice that the
(line 664) NOTE: Pressing v starts Visual selection. You can move the cursor around
(line 676) NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
(line 752) 5. Use e to move to the next incomplete word and repeat steps 3 and 4.
(line 791) 2. Start Visual mode with v and move the cursor to just before "first".
(line 799) 6. Use Visual mode to select " item.", yank it with y , move to the end of
Enter word to look for, or q to quit: q
[textquery]$