C++primer 文本查询练习

来源:互联网 发布:高超音速 知乎 编辑:程序博客网 时间:2024/05/18 02:53

// header file

#pragma once
#include "TextQuery.h"
#include <algorithm>
#include <iterator>



namespace StringQuery{

    class QueryBase
    {
        friend class Query;
    protected:
        typedef TextQuery::line_no line_no;
        virtual ~QueryBase(void){};
    private:
        virtual std::set<line_no> eval(const TextQuery& t) const = 0;
        virtual std::ostream& display(std::ostream& os = std::cout) const = 0;
    };


    class Query
    {
    public:
        friend Query operator~(const Query& );

        friend Query operator|(const Query& ,const Query& );

        friend Query operator&(const Query& ,const Query& );

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

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

        Query& operator=(const Query &);

    public:
        Query(const std::string &s);

        Query(const Query& query):q(query.q),use(query.use){++*use;}

        Query(QueryBase* qb):q(qb),use(new size_t(1)){}

        ~Query(void){decr_use();}

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

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

    inline Query& Query::operator=(const Query &rhs)
    {
        ++*rhs.use;
        decr_use();
        q = rhs.q;
        use = rhs.use;
        return *this;
    }

    class WordQuery:public QueryBase
    {
        friend class Query;
        WordQuery(const std::string &s):query_word(s) { }

        std::set<line_no> eval(const TextQuery &t) const
        { return t.run_query(query_word); }

        std::ostream& display(std::ostream &os = std::cout) const
        { return os << query_word; }

        std::string query_word;
    };

    inline
    Query::Query(const std::string &s):q(new WordQuery(s)),
                                    use(new std::size_t(1)) { }


    class NotQuery:public QueryBase
    {
        friend Query operator~(const Query& query);

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

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

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


        const Query query;//implemente binding
    };


    class BinaryQuery:public QueryBase
    {
    protected:
        BinaryQuery(const Query &rl,const Query &rr,const std::string &op):rhl(rl),rhr(rr),oper(op){}

        std::ostream& display(std::ostream &os) const
        { return os << "~(" << rhl << "" << oper << " " << rhr << ")"; }

        const Query rhl,rhr;
        const std::string oper;
    };

    class OrQuery:public BinaryQuery
    {
        friend Query operator|(const Query &,const Query &);

        OrQuery(const Query& rl,const Query& rr):BinaryQuery(rl,rr,"|"){}

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

    class AndQuery:public BinaryQuery
    {
        friend Query operator&(const Query &,const Query &);

        AndQuery(const Query &rl,const Query &rr):BinaryQuery(rl,rr,"&"){}

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

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

    inline Query operator|(const Query& query_left,const Query& query_right)
    { return new OrQuery(query_left,query_right); }

    inline Query operator&(const Query& query_left,const Query& query_right)
    { return new AndQuery(query_left,query_right); }

    Query parse_expression(const std::string &QueryString);
}

// cpp file

#include "Query.h"
#include "TextQuery.h"
#include <set>
#include <algorithm>
#include <iostream>

using std::set;
using std::vector;
using std::string;
using std::ostream;
using std::inserter;
using std::set_difference;
using std::set_union;
using std::set_intersection;

namespace StringQuery{

    set<TextQuery::line_no> NotQuery::eval(const TextQuery &file) const
    {
        set<line_no> has_val = query.eval(file);
        set<line_no> not_val;
        for(line_no lineSum = 0;lineSum < file.size();++lineSum)
        {
            if( has_val.find(lineSum)==has_val.end() )
                not_val.insert(lineSum);
        }
        return not_val;
    }

    set<TextQuery::line_no> OrQuery::eval(const TextQuery &file) const
    {
        set<line_no> right = rhr.eval(file),
            ret_lines = rhl.eval(file);
        ret_lines.insert( right.begin(),right.end() );

        return ret_lines;
    }

    set<TextQuery::line_no> AndQuery::eval(const TextQuery &file) const
    {
        set<line_no> rval = rhr.eval(file),
            lval = rhl.eval(file);
        set<line_no> retlines;

        set_intersection( rval.begin(),rval.end(),lval.begin(),lval.end(),inserter(retlines,retlines.begin()) );

        return retlines;
    }

    bool inputValidate(const std::string &QueryString)
    {
        std::string::size_type pos = QueryString.find("~|&");
        if(std::string::npos != pos)
            if( std::string::npos != QueryString.find("~|&",++pos) )
                return false;
        return true;
    }

    Query parse_expression(const std::string &QueryString)
    {
        vector<string> words;
        vector<string> opers;
        string::size_type pos_pre = 0;
        string::size_type pos_cur = QueryString.find_first_of("~|&");
        while(string::npos != pos_cur)
        {
            string word = QueryString.substr( pos_pre,pos_cur - pos_pre );
            words.push_back(word);
            string oper = QueryString.substr(pos_cur,1);
            opers.push_back(oper);
            pos_pre = pos_cur+1;
            pos_cur = QueryString.find_first_of("~|&",pos_pre);
        }
        string word = QueryString.substr(pos_pre,QueryString.size()-pos_pre);
        words.push_back(word);

        vector<string>::const_reverse_iterator words_it = words.rbegin();
        vector<string>::const_reverse_iterator opers_it = opers.rbegin();
        Query query(*words_it);
        words_it++;
        for(;words_it != words.rend();words_it++)
        {
            if( opers_it != opers.rend() )
            {
                switch((*opers_it).at(0))
                {
                case '~':
                    query = ~query;
                    break;
                case '|':
                    query = query|Query(*words_it);
                    words_it++;
                    break;
                case '&':
                    query = query&Query(*words_it);
                    words_it++;
                    break;
                default:
                    std::cerr << "It's an operator from Mars!";
                }
                opers_it++;
            }
        }

        //Query query( *(new string("temp")) );
        return query;
    }

}

 

 

// Finder.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <conio.h>
#include "TextQuery.h"
#include "Query.h"
//#include <boost/regex.hpp>
//using namespace boost;
using std::string;
using std::set;
using std::cin;
using std::cout;
using std::endl;

void printResult(const string& word,const char* filename);

int _tmain(int argc, _TCHAR* argv[])
{
    if(3 > argc)
    {
        cout << "Usage:program <Filename> <QueryWord> ." << endl;
    }
    else
    {
        string word;
        for(int count = 2;count < argc;count++)
        {
            word += argv[count];
        }
        StringQuery::Query q( StringQuery::parse_expression(word) );
        TextQuery tq;
        tq.readFile(argv[1]);
        q.display(std::cout);
        set<TextQuery::line_no> rec = q.eval(tq);
        set<TextQuery::line_no>::iterator it = rec.begin();
        for(;it != rec.end();++it)
        {
            cout << " ( line " << *it << " ) " << tq.textLine(*it) << endl;
        }
    }

    _getch();
    return 0;
}

void printResult(const string& word,const char* filename)
{
    TextQuery tq;
    tq.readFile(filename);
    set<TextQuery::line_no> res = tq.run_query(word);
    cout << "Found " << res.size() << " items." << endl;
    set<TextQuery::line_no>::iterator it = res.begin();
    for(;it != res.end();++it)
    {
        cout << " ( line " << *it << " ) " << tq.textLine(*it) << endl;
    }

}

原创粉丝点击