C++ primer第四版15.9节案例吐血实现

来源:互联网 发布:什么是电子数据交换 编辑:程序博客网 时间:2024/06/06 03:41
 原帖地址

http://blog.csdn.net/clhposs/article/details/5258325 

 

 

#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <cstddef>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <numeric>

class TextQuery
{
 typedef std::map<std::string, std::set<std::size_t> > Type;
public:
 void read_file(const std::string &strPath)
 {
  get_data(strPath);
 }
 std::string get_str(std::size_t i) const;
 std::set<std::size_t> get_lines(const std::string &word);
 std::size_t size() const
 {
  return lines.size();
 }
private:
 void get_data(const std::string &strPath);
private:
 std::vector<std::string> lines;
 Type words; 
};

void TextQuery::get_data(const std::string &strPath)
{
 std::ifstream read(strPath.c_str());

 if (!read)
  return;

 std::string str_line;
 std::size_t index = -1;
 while (std::getline(read, str_line))
 {
  ++index;
  lines.push_back(str_line);
  std::istringstream str_word(str_line);
  std::string word;
  while ( str_word >> word)
  {
   words[word].insert(index);
  }
 }

 read.close();
}

std::string TextQuery::get_str(std::size_t i) const
{
 return lines[i];
}

std::set<std::size_t> TextQuery::get_lines(const std::string &word)
{
 return words[word];
}

class Query_Base
{
 friend class Query;
protected:
 virtual ~Query_Base() { }
private:
 virtual std::set<std::size_t> eval(TextQuery &text) = 0;
 virtual void display(std::ostream &os = std::cout) = 0;
};

class WordQuery: public Query_Base
{
 friend class Query;
private:
 WordQuery(const std::string &str): word(str) { }
 virtual std::set<size_t> eval(TextQuery &text)
 {
  return text.get_lines(word);
 }
 virtual void display(std::ostream &os = std::cout)
 {
  os << word;
 }
 std::string word;
 virtual ~WordQuery() { }
};

class Query
{
 friend Query operator|(const Query &que1, const Query &que2);
 friend Query operator&(const Query &que1, const Query &que2);
 friend Query operator~(const Query &que);
public:
 Query(const std::string &word): p(new WordQuery(word)), use(new std::size_t(1)) { }
 Query(const Query &query): p(query.p), use(query.use) { ++*use; }
 Query& operator=(const Query &query)
 {
  ++*use;
  del_use();
  p = query.p;
  use = query.use;
 }
 std::set<std::size_t> eval(TextQuery &text)
 {
  return p->eval(text);
 }
 void display(std::ostream& os = std::cout)
 {
  p->display(os);
 }
private:
 Query(Query_Base *base): p(base), use(new std::size_t(1)) { }
 Query_Base * p;
 std::size_t *use;
 void del_use()
 {
  if (--*use == 0)
  {
   delete p;
   delete use;
  }
 }
};

std::ostream& operator<<(std::ostream& os, Query &que)
{
 que.display(os);
 return os;
}

class NotQuery: public Query_Base
{
 friend Query operator~(const Query &query);
private:
 NotQuery(Query que):query(que) { }
 virtual std::set<std::size_t> eval(TextQuery &text);
 virtual void display(std::ostream &os /* = std::cout */)
 {
  os << "( ~" << query << " )";
 }
 Query query;
};

class BinaryQuery: public Query_Base
{
protected:
 BinaryQuery(Query lf, Query rh, std::string op): left(lf), right(rh), oper(op) { }
 virtual void display(std::ostream &os /* = std::cout */)
 {
  os << "( " << left << oper << right << " )";
 }
  Query left;
 Query right;
 std::string oper;
};

class AndQuery: public BinaryQuery
{
 friend Query operator&(const Query &que1, const Query &que2);
private:
 AndQuery(Query lf, Query rg): BinaryQuery(lf, rg, "&")
 {}
 virtual std::set<std::size_t> eval(TextQuery &text);
};

class OrQuery: public BinaryQuery
{
 friend Query operator|(const Query &que1, const Query &que2); 
private:
 OrQuery(Query lf, Query rg): BinaryQuery(lf, rg, "|")
 {}
 virtual std::set<std::size_t> eval(TextQuery &text);
};

Query operator|(const Query &que1, const Query &que2)
{
 return new OrQuery(que1, que2);
}

Query operator&(const Query &que1, const Query &que2)
{
 return new AndQuery(que1, que2);
}

Query operator~(const Query &que)
{
 return new NotQuery(que);
}

std::set<std::size_t> AndQuery::eval(TextQuery &text)
{
 std::set<std::size_t> rg = right.eval(text), lft = left.eval(text);
 std::set<std::size_t> sum;

 std::set_intersection(rg.begin(), rg.end(), lft.begin(), lft.end(), std::inserter(sum, sum.end()));

 return sum;
}

std::set<std::size_t> OrQuery::eval(TextQuery &text)
{
 std::set<std::size_t> rg = right.eval(text), lft = left.eval(text);
 lft.insert(rg.begin(), rg.end());

 return lft;
}

std::set<std::size_t> NotQuery::eval(TextQuery &text)
{
 std::set<std::size_t> word_line = query.eval(text), not_line;

 for (std::size_t i = 0; i != text.size(); ++i)
 {
  if (word_line.find(i) == word_line.end())
  {
   not_line.insert(i);
  }
 }

 return not_line;
}

int main()
{
 std::string strPath;
 std::cin >> strPath;

 TextQuery text;
 text.read_file(strPath);
 
 Query find = Query("timeout=3") | Query("[boot");

 std::cout << find << std::endl;
 std::set<std::size_t> line = find.eval(text);

 for (std::set<std::size_t>::iterator iter = line.begin(); iter != line.end(); ++iter)
 {
  std::cout << "<line " << *iter << ">"<< text.get_str(*iter) << std::endl;
 }

 system("pause");
 return 0;
}