C++ primer 文本查询程序 Query

C++ primer 文本查询程序,面向对象的实现,有很多值得学习的知识点。

整理了代码如下,使用VS2010,g++编译通过:


#include <map>
#include <set>
#include <vector>
#include <string>

#include <algorithm>
#include <iterator>
#include <istream>
#include <sstream>  //istringstream
using std::istringstream;

using std::map;
using std::set;
using std::vector;
using std::string;

#include <iostream>
using std::ostream;
using std::cout;
using std::cin;
using std::cerr;
using std::endl;

#include <fstream>
using std::getline;
using std::ifstream;


/**
 * @brief The TextQuery class
 */
class TextQuery
{
public:
    typedef vector<string>::size_type line_no;
    void read_file(std::ifstream &is)
    {
        store_file(is);
        build_map();
    }

    set<line_no> run_query(string &) const;
    string text_line(line_no) const;
    line_no size() const   //the total lines num
    {
        return lines_of_text.size();
    }

private:
    void store_file(std::ifstream &);
    void build_map();
    vector<string> lines_of_text;
    map<string,set<line_no> > word_map;
};


set<TextQuery::line_no> TextQuery::run_query(string &query_word) const
{
    map<string,set<line_no> >::const_iterator iter = word_map.find(query_word);
    if ( iter != word_map.end() )
    {
        return iter->second;
    }

    return set<line_no>();
}
string TextQuery::text_line(line_no line) const
{
    return lines_of_text[line];
}

void TextQuery::store_file(std::ifstream &is)
{
    string textline;
    while ( getline(is,textline) )
    {
        lines_of_text.push_back(textline);
    }
}

void TextQuery::build_map()
{
    line_no line_num = 0;
    for ( ; 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);
        }
    }
}




/**
 * @brief The Query_base class
 */
class Query_base
{
    friend class Query;
protected:
    virtual ~Query_base()
    {

    }

private:
    virtual set<TextQuery::line_no> eval(const TextQuery &) const = 0;
    virtual ostream & display(ostream &os = std::cout ) const = 0;
};


class Query
{
    friend Query operator~(const Query &);
    friend Query operator|(const Query &,const Query &);
    friend Query operator&(const Query &,const Query &);

public:
    Query(const string &word); //builds a new wordQuery

    //copy control to manage pointers and counting
    Query(const Query &c):q(c.q),use(c.use)
    {
        ++*use;
    }

    ~Query()
    {
        decr_use();
    }

    Query &operator=(const Query &query)
    {
        q = query.q;
        ++*use;
        return *this;
    }

    set<TextQuery::line_no> eval(const TextQuery &t) const
    {
        return q->eval(t);
    }

    std::ostream &display(std::ostream &os) const
    {
        return q->display(os);
    }

private:
    Query(Query_base *query):q(query),use(new std::size_t(1))
    {

    }
    Query_base *q;
    std::size_t *use;
    void decr_use()
    {
        if ( --*use == 0 )
        {
            delete q;
            delete use;
        }
    }
};

inline ostream & operator<<(ostream &os,const Query &query)   //why needed const for Query &??
{
    query.display(os);
    return os;
}

/**
 * @brief The WordQuery class
 */
class WordQuery : public Query_base
{
    friend class Query;
    WordQuery(const string &s):query_word(s)
    {

    }

    set<TextQuery::line_no> eval(const TextQuery &t) const
    {
        return t.run_query((string &)query_word);   //why needed const?
    }
    ostream & display(ostream &os = std::cout ) const;
    string query_word;
};

ostream & WordQuery::display(ostream &os) const
{
    return os<<query_word;
}

//Query constructor!! we can't define before the WordQuery class finish
Query::Query(const string &word) //builds a new wordQuery
{
    q = new WordQuery(word);
    use = new std::size_t(1);
}

/**
 * @brief The NotQuery class
 */
class NotQuery :public Query_base
{
    friend Query operator~(const Query &);
    NotQuery(const Query &q):query(q)
    {

    }

    set<TextQuery::line_no> eval(const TextQuery &) const;   //becareful the last const,if you forget to add it in the implement,it overloads and bug
    ostream & display(ostream &os) const;
    const Query query;   //const is ok,when you initianize in the constructor
};

set<TextQuery::line_no> NotQuery::eval(const TextQuery &file) const
{
    set<TextQuery::line_no> has_val = query.eval(file);
    set<TextQuery::line_no> ret_lines;

    TextQuery::line_no n = 0;
    for ( ; n != file.size() ; ++n )
    {
        if ( has_val.find(n) == has_val.end() )
        {
            ret_lines.insert(n);
        }
    }

    return ret_lines;
}

ostream & NotQuery::display(ostream &os) const
{
    return os<<"~("<<query<<")";
}

/**
 * @brief The BinaryQuery class
 */
class BinaryQuery : public Query_base
{
protected:   //can't not be private
    BinaryQuery(Query left,Query right,string op):lhs(left),rhs(right),oper(op)
    {

    }

    ostream & display(ostream &os = std::cout ) const
    {
        return os<<"("<<lhs<<" "<<oper<<" "<<rhs<<")";
    }

    Query lhs,rhs;
    string oper;   //& |
};

/**
 * @brief The AndQuery class
 */
class AndQuery : public BinaryQuery
{
    friend Query operator&(const Query &,const Query &);
    AndQuery(const Query &left,const Query &right):BinaryQuery(left,right,"&")
    {

    }

    set<TextQuery::line_no> eval(const TextQuery &) const;
};


set<TextQuery::line_no> AndQuery::eval(const TextQuery &file) const
{
    set<TextQuery::line_no> left = lhs.eval(file),
    right = rhs.eval(file);

    set<TextQuery::line_no> ret_lines;
    set_intersection(left.begin(),left.end(),right.begin(),right.end(),inserter(ret_lines,ret_lines.begin()));

    return ret_lines;
}

/**
 * @brief The OrQuery class
 */
class OrQuery : public BinaryQuery
{
    friend Query operator|(const Query &,const Query &);
    OrQuery(const Query lq,const Query rq):BinaryQuery(lq,rq,"|")
    {

    }

    set<TextQuery::line_no> eval(const TextQuery &) const;
};


set<TextQuery::line_no> OrQuery::eval(const TextQuery &file) const
{
    set<TextQuery::line_no> right = lhs.eval(file),
    ret_lines = rhs.eval(file);

    ret_lines.insert(right.begin(),right.end());
    return ret_lines;
}

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

Query operator|(const Query &lhr,const Query &rhr)
{
    return new OrQuery(lhr,rhr);
}

Query operator&(const Query &lhr,const Query &rhr)
{
    return new AndQuery(lhr,rhr);
}


void print_result(const set<TextQuery::line_no> &locs,const TextQuery &file)
{
    typedef set<TextQuery::line_no> line_nums;
    line_nums::const_iterator iter = locs.begin();
    for( ; iter != locs.end() ; iter++ )
    {
        cout<<"\tline"<<(*iter)+1<<")"<<file.text_line(*iter)<<endl;
    }
}

bool open_file(ifstream &is,char *filename)
{
    if ( is.is_open() )
    {
        is.close();
    }

    is.open(filename);

    if ( is.is_open() == true )
    {
        return true;
    }

    return false;
}


int main()
{

    ifstream infile;
    if ( !open_file(infile,(char *)"TextQuery.txt"))
    {
        cerr<<"No input file!"<<endl;
        return -1;
    }

    TextQuery tq;
    tq.read_file(infile);

    //Query q = Query("I") & Query("like") | Query("you");
    //Query q = Query("you") & Query("like");
    Query q = Query("I") & Query("like");
    set<TextQuery::line_no> res = q.eval(tq);
    q.display(cout);

    cout<<endl;
    print_result(res,tq);
}

测试文件为 TextQuery.txt ,内容如下,

I like you and hope you like me!
But you don't like me,I know that,I am so sad!
One day,will you like me?




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值