c++primer里的文本查询程序扩展

感觉这个例子很锻炼面向对象思想,所以还是写下来吧

Query_base.h

#pragma once

# include"TextQuery.h"
# include"QueryResult.h"
# include<string>

//这是一个抽象基类,具体的查询类型从中派生,所有成员都是private的
class Query_base
{
    friend class Query;
protected:
    using line_no = TextQuery::line_no; //用于eval函数
    virtual ~Query_base() = default;
private:
    //eval返回与当前Query匹配的QueryResult
    virtual QueryResult eval(const TextQuery &)const = 0;
    virtual std::string rep()const = 0;
};

Query.h

#pragma once
# include<string>
# include"QueryResult.h"
# include"TextQuery.h"
# include"Query_base.h"
# include<iostream>

//这是一个管理Query_base继承体系的的接口类
class Query
{
    //这些运算符需要访问接受shared_ptr的构造函数,而该函数是私有的
    friend Query operator~(const Query&);
    friend Query operator|(const Query&,const Query&);
    friend Query operator&(const Query&, const Query&);
public:
    Query(const std::string&);//构建一个新的WordQuery

    //接口函数:调用对应的Query_base操作
    QueryResult eval(const TextQuery&t)const;
    std::string rep()const;
private:
    Query(std::shared_ptr<Query_base> query);
    std::shared_ptr<Query_base> q;
};

Query.cpp

# include"Query.h"
# include"WordQuery.h"
# include<string>
# include<iostream>

QueryResult Query::eval(const TextQuery&t)const
{
    return q->eval(t);
}
std::string Query::rep()const
{
    return q->rep();
}

Query::Query(const std::string&s):q(new WordQuery(s))
{}

std::ostream&operator<<(std::ostream&os, const Query&query)
{
    //Query::rep通过它的Query_base指针对rep()进行了虚调用
    return os << query.rep();
}

Query::Query(std::shared_ptr<Query_base> query) :q(query) {}

TextQuery.h

# pragma once

# include"QueryResult.h"
# include<vector>
# include<fstream>
# include<memory>
# include<map>
# include<set>

class QueryResult;//为了定义函数query的返回类型,这个定义是必须的
class TextQuery
{
public:
    using line_no = std::vector<std::string>::size_type;
    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.cpp

# include"TextQuery.h"
# include<vector>
# include<string>
# include<sstream>
# include"QueryResult.h"
class QueryResult;
using namespace std;

TextQuery::TextQuery(ifstream &is):file(new vector<string>)
{
    string text;
    while (getline(is, text))   //对文件中每一行
    {
        file->push_back(text);  //保存此行文本
        int n = file->size() - 1;   //当前行号
        istringstream line(text);   //将行文本分解为单词
        string word;
        while (line >> word)    //对行中每个单词
        {
            //如果单词不在wm中,以之为下标在wm中添加一项
            auto &lines = wm[word];//lines是一个sharred_ptr
            if (!lines) //在我们第一次遇到这个单词时,此指针为空
                lines.reset(new set < line_no>);//分配一个新的set
            lines->insert(n);   //将此行号插入set中    
        }
    }
}

QueryResult TextQuery::query(const string &sought)const
{
    //如果未找到sought,我们将返回一个指向此set的指针
    static shared_ptr<set<line_no>> nodata(new set<line_no>);
    //使用find而不是下标运算符来查找单词,避免将单词添加到wm中
    auto loc = wm.find(sought);
    if (loc == wm.end())
        return QueryResult(sought, nodata, file);   //未找到
    else return
        QueryResult(sought, loc->second, file);
}

QueryResult.h

# pragma once

# include<iostream>
# include"TextQuery.h"
# include<memory>
# include<set>
# include<vector>
# include<string>

class QueryResult
{
    friend std::ostream& print(std:: ostream &, const QueryResult&);
public:
    using size = std::vector<std::string>::size_type;
    QueryResult(std::string s,
        std::shared_ptr<std::set<size>> p,
        std::shared_ptr<std::vector<std::string>> f);

    std::set<size>::iterator begin();
    std::set<size>::iterator end();
    std::shared_ptr<std::vector<std::string>> get_file();
private:
    std::string sought;//查询单词
    std::shared_ptr<std::set<size>> lines;//出现的行号
    std::shared_ptr<std::vector<std::string>> file; //输入文件
};

QueryResult.cpp

# include"QueryResult.h"
# include"TextQuery.h"
using size = std::vector<std::string>::size_type;
QueryResult::QueryResult(std::string s,
    std::shared_ptr<std::set<size>> p,
    std::shared_ptr<std::vector<std::string>> f):sought(s), lines(p), file(f)
    {}

std::set<size>::iterator QueryResult::begin()
{
    return this->lines->begin();
}
std::set<size>::iterator QueryResult::end()
{
    return this->lines->end();
}

std::shared_ptr<std::vector<std::string>> QueryResult::get_file()
{
    return this->file;
}

WordQuery.h

#pragma once
# include"Query_base.h"
# include<string>

class WordQuery:public Query_base
{
    friend class Query; //Query使用WordQuery构造函数
    WordQuery(const std::string &s);
    //具体的类:WordQuery将定义所有继承+而来的纯虚函数
    QueryResult eval(const TextQuery&t)const;
    std::string rep()const;
    std::string query_word; //要查找的单词
};

WordQuety.cpp

# include"WordQuery.h"

WordQuery::WordQuery(const std::string &s) :query_word(s) {}

//具体的类:WordQuery将定义所有继承而来的纯虚函数
QueryResult WordQuery::eval(const TextQuery&t)const
{
    return t.query(query_word);
}
std::string WordQuery::rep()const
{
    return query_word;
}

BinaryQuery.h

# pragma once
# include"Query.h"
# include"Query_base.h"

class BinaryQuery:public Query_base
{
protected:
    BinaryQuery(const Query &l, const Query &r, std::string s);
    //抽象类:BinaryQuery不定义eval
    std::string  rep()const;
    Query lhs,rhs;  //右侧和左侧运算对象
    std::string opSym;  //运算符的名字
};

BinaryQuery.cpp

# include"BinaryQuery.h"

BinaryQuery::BinaryQuery(const Query &l, const Query &r, std::string s) :
    lhs(l), rhs(r), opSym(s) {}

std::string  BinaryQuery::rep()const
{
    return "(" + lhs.rep() + " " + opSym + " " + rhs.rep() + ")";
}

AndQuery.h

#pragma once
# include"BinaryQuery.h"

class AndQuery:public BinaryQuery
{
    friend Query operator&(const Query&, const Query&);
    AndQuery(const Query&left, const Query&right);
    //具体的类:AndQuery继承了rep并且定义了其他纯虚函数
    QueryResult eval(const TextQuery&)const;
};

AndQuery.cpp

# include"AndQuery.h"
# include<set>
# include<memory>
# include<algorithm>
# include<iterator>

AndQuery::AndQuery(const Query&left, const Query&right) :
    BinaryQuery(left, right, "&") {}

Query operator&(const Query&lhs, const Query &rhs)
{
    return std::shared_ptr<Query_base>(new AndQuery(lhs, rhs));
}

QueryResult AndQuery::eval(const TextQuery&text)const
{
    //通过Query运算对象进行的虚调用,以获得运算对象的查询结果set
    auto left = lhs.eval(text), right = rhs.eval(text);
    //保存left和right的交集的set
    auto ret_lines = std::make_shared<std::set<line_no>>();

    //将两个范围的交集写入一个目的迭代器中
    //本次调用的目的迭代器向ret添加元素
    std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
        inserter(*ret_lines, ret_lines->begin()));
    return QueryResult(rep(), ret_lines, left.get_file());
}

OrQuery.h

#pragma once
# include"BinaryQuery.h"

class OrQuery :public BinaryQuery
{
    friend Query operator|(const Query&, const Query&);
    OrQuery(const Query&left, const Query&right);
    //具体的类:AndQuery继承了rep并且定义了其他纯虚函数
    QueryResult eval(const TextQuery&)const;
};

OrQuery.cpp

# include"OrQuery.h"
# include<memory>
# include<set>
# include"BinaryQuery.h"
# include"Query_base.h"
# include"Query.h"

OrQuery::OrQuery(const Query&left, const Query&right) :
    BinaryQuery(left, right, "|") {}

QueryResult OrQuery::eval(const TextQuery&text)const
{
    //通过Query成员lhs和rhs进行的虚调用
    //调用eval返回每个运算对象的QueryResult
    auto right = rhs.eval(text), left = lhs.eval(text);
    //将左侧运算对象的行号拷贝到结果Set中
    auto ret_lines = std::make_shared<std::set<line_no>>(left.begin(), left.end());
    //插入右侧运算对象所得的行号
    ret_lines->insert(right.begin(), right.end());
    //返回一个新的QueryResult,它表示lhs和rhs的并集
    return QueryResult(rep(), ret_lines, left.get_file());
}

 Query operator|(const Query&lhs, const Query &rhs)
{
    return std::shared_ptr<Query_base>(new OrQuery(lhs, rhs));
}

NotQuery.h

#pragma once
# include"Query_base.h"
# include"Query.h"

class NotQuery:public Query_base
{
    friend Query operator~(const Query&);
    NotQuery(const Query&q);
    //具体的类:NotQuery将定义所有继承而来的纯虚函数
    std::string rep()const;
    QueryResult eval(const TextQuery&) const;
    Query query;
};

NotQuery.cpp

# include"NotQuery.h"
# include<memory>
# include<set>
# include"QueryResult.h"
class QueryResult;

NotQuery::NotQuery(const Query&q) :query(q) {}

std::string NotQuery::rep()const
{
    return "~(" + query.rep() + ")";
}

QueryResult
NotQuery::eval(const TextQuery&text)const
{
    auto result = query.eval(text);
    auto ret_lines=std::make_shared<std::set<line_no>>();
    auto beg = result.begin(), end = result.end();
    auto sz = result.get_file()->size();
    for (size_t n = 0;n != sz;++n)
    {
        if (beg == end || *beg != n)
            ret_lines->insert(n);
        else if (beg != end)++beg;
    }
    return QueryResult(rep(), ret_lines, result.get_file());
}

Query operator~(const Query&operand)
{
    //return std::shared_ptr<Query_base>(new NotQuery(operand));
    //等价于:
    std::shared_ptr<Query_base> tmp(new NotQuery(operand));
    return Query(tmp);
}

先来查找单个单词,main.cpp

# include<iostream>
# include<fstream>
# include<string>
# include"Query.h"
# include"QueryResult.h"
# include"TextQuery.h"
# include"WordQuery.h"
using namespace std;

std::ostream& print(std::ostream &, const QueryResult&);
std::string make_plural(size_t i, const std::string &word, const std::string &end)
{
    return i == 1 ? word : word + end;
}

int main()
{
    std::ifstream fin("E:\\项目\\c++\\文本查询程序2\\文本查询程序2\\file.txt");
    TextQuery text(fin);

    Query a1("windows");
    Query a2("class");
    Query b1=~a1;
    Query b2 = a1&a1;
    Query b3 = a1 | a1;

    auto s = a1.rep();
    cout << s << endl;

    const auto result = a1.eval(text);
    print(std::cout, result);

    fin.close();

    system("pause");
    return 0;
}


std::ostream& print(std::ostream &os, const QueryResult&qr)
{
    os << qr.sought << " occus " << qr.lines->size() << " "\
        << make_plural(qr.lines->size(), "time", "s") << std::endl;
    for (auto num : *qr.lines)
        os << "\t(line " << num + 1 << ")\t" << *(qr.file->begin() + num) << std::endl;
    return os;
}

查找单词windows:
这里写图片描述

接下来查找没有单词a1的:
这里写图片描述

查找同时出现a1和a2:
这里写图片描述
查找出现a1或a2:
这里写图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值