C++ Primer 文本查询程序
运行效果
源码
#include <iostream>
#include <vector>
#include <fstream>
#include <map>
#include <set>
#include <string>
#include <memory>
#include <sstream>
#include <format>
#include <iomanip>
#include <Windows.h>
using line_no = std::vector<std::string>::size_type;
class QueryResult
{
friend std::ostream& operator<<(std::ostream&, const QueryResult&);
public:
QueryResult(std::string s,
std::shared_ptr<std::set<line_no>> p,
std::shared_ptr<std::vector<std::string>> f) :
sought(s), lines(p), file(f)
{}
private:
std::string sought; // 要查询的单词
std::shared_ptr<std::set<line_no>> lines;
std::shared_ptr<std::vector<std::string>> file;
};
std::string make_plural(size_t ctr, const std::string& word, const std::string& ending)
{
return (ctr > 1) ? word + ending : word;
}
void print_line(const std::string& line, const std::string& target)
{
auto add_background_color = [](const std::string& word) {
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
WORD wOldColorAttrs;
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
// Get the current color
GetConsoleScreenBufferInfo(h, &csbiInfo);
wOldColorAttrs = csbiInfo.wAttributes;
// Set the new color
SetConsoleTextAttribute(h, FOREGROUND_GREEN | BACKGROUND_RED);
std::cout << word;
// Restore the original color
SetConsoleTextAttribute(h, wOldColorAttrs);
};
std::istringstream ss(line);
std::string word;
while (ss >> word) {
if (word == target) add_background_color(word);
else std::cout << word;
std::cout << " ";
}
}
std::ostream& operator<<(std::ostream& os, const QueryResult& qr)
{
os << std::quoted(qr.sought) << " occurs " << qr.lines->size() << " "
<< make_plural(qr.lines->size(), "time", "s") << " : \n";
const auto num_width = std::to_string(qr.file->size()).size();
for (const auto num : *qr.lines) {
os << std::format("\t(line {:>{}}) ", num + 1, num_width);
print_line((*qr.file)[num], qr.sought);
os << "\n";
}
return os;
}
class TextQuery {
public:
TextQuery(std::ifstream&);
QueryResult query(const std::string&) const;
private:
std::shared_ptr<std::vector<std::string>> file;
std::map<std::string, std::shared_ptr<std::set<line_no>>> wm;
};
TextQuery::TextQuery(std::ifstream& is) :
file(new std::vector<std::string>)
{
std::string text; // 每行
while (std::getline(is, text)) {
file->push_back(text);
auto n = file->size() - 1;
std::istringstream line(text);
std::string word;
while (line >> word) {
auto& line_nos = wm[word];
if (!line_nos) line_nos.reset(new std::set<line_no>);
line_nos->insert(n);
}
}
}
QueryResult TextQuery::query(const std::string& sought) const
{
static std::shared_ptr<std::set<line_no>> nodata(new std::set<line_no>);
auto loc = wm.find(sought);
if (loc == wm.end()) return QueryResult(sought, nodata, file);
return QueryResult(sought, loc->second, file);
}
void runQueries(std::ifstream& infile)
{
TextQuery tq(infile);
while (true) {
std::cout << "Enter word to look for, or q to quit: ";
std::string word;
if (!(std::cin >> word) || word == "q") break;
std::cout << tq.query(word) << std::endl;
}
}
int main()
{
const std::string filename{R"(E:\Desktop\text.txt)"};
std::ifstream file(filename);
if (file.is_open())
runQueries(file);
else
std::cerr << "open file failed!\n";
}