C++ Primer 第15章例子-文本查询程序

标签: c++querystringclassfileiterator
2971人阅读 评论(3) 收藏 举报
分类:

1. Main.cpp

#include "TextQuery.h"
#include <fstream>
#include "QueryAll.h"

using namespace std;

void print_result(const set<TextQuery::line_no>& locs, const string& sought, const TextQuery& file)
{
	typedef set<TextQuery::line_no> line_nums;
	line_nums::size_type size = locs.size();
	cout<<"\n"<<sought<<" occurs "<<size<<(size>1?"Times":"Time")<<endl;
	line_nums::const_iterator it = locs.begin();
	for(; it!=locs.end(); ++it)
		cout<<(*it)+1<<"\t"<<file.text_line(*it)<<endl;
}

int main()
{
    ifstream is("text.txt");
    TextQuery tq;
    tq.read_file(is);
    Query q = Query("The") & Query("of") | Query("the");
    std::set<TextQuery::line_no> locs = q.eval(tq);
    string s("((fiery & bird) | wind)");
    print_result(locs, s, tq);
/*	ifstream infile("text.txt");
	if(!infile)
	{
		cout<<"No Input File!"<<endl;
		return -1;
	}
	TextQuery tq;
	tq.read_file(infile);
	while(true) {
		cout<<"Enter word to query, or q to quit: ";
		string s;
		cin>>s;
		if(!cin || s=="q")
			break;
		set<TextQuery::line_no> locs = tq.run_query(s);
		print_result(locs, s, tq);
	}*/
	while(true) {
        int i;
        cin>>i;
    };
	return 0;
}

2. TextQuery.h

#pragma once

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

class TextQuery {
public:
	typedef std::vector<std::string>::size_type line_no;
	void read_file(std::ifstream &is) {store_file(is); build_map();}
	std::set<line_no> run_query(const std::string&) const;
	std::string text_line(line_no) const;
	line_no size() const { return lines_of_text.size(); }

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

3. TextQuery.cpp

#include "TextQuery.h"
#include <fstream>
#include <sstream>

using namespace std;

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

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

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

string TextQuery::text_line(line_no line) const
{
	if(line < lines_of_text.size())
		return lines_of_text[line];
	return NULL;
}

4. QueryAll.h

// Query.h

#ifndef QUERY_H
#define QUERY_H

#include "TextQuery.h"
#include <string>
#include <set>
#include <iostream>
#include <fstream>

///////////////////////////////////////////////////////////////////////////////////
// class QueryBase: private, abstract class acts as a base for concrete query types
class QueryBase
{
    friend class Query;
protected:
    typedef TextQuery::line_no line_no;
    virtual ~QueryBase() {}
private:
    // eval returns the |set| of lines that this Query matches
    virtual std::set<line_no> eval(const TextQuery&) const = 0;
    virtual std::ostream& display(std::ostream& = std::cout) const = 0;
};

///////////////////////////////////////////////////////////////////////////////////
// class Query
class Query
{
    // these operators need access to the QueryBase's constructor
    friend Query operator~ (const Query&);
    friend Query operator| (const Query&, const Query&);
    friend Query operator& (const Query&, const Query&);
    
public:
    // builds a new WordQuery
    Query(const std::string&);
    // copy control to manage pointers and reference counting
    Query(const Query &c): q(c.q), use(c.use) {
        ++*use;
    }
    ~Query() {
        decr_use();
    }
    Query& operator= (const Query&);
    // interface functions: will call corresponding QueryBase operations
    std::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(QueryBase *query): q(query), use(new std::size_t(1)) {}
    QueryBase * q;
    std::size_t *use;
    void decr_use() {
        if (--*use == 0) {
            delete q;
            delete use;
        }
    }
};

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

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

/////////////////////////////////////////////////////////////////////////////////
// class WordQuery
class WordQuery: public QueryBase
{
    friend class Query; // Query uses the WordQuery constructor
private:
    WordQuery(const std::string &s): query_word(s) { }
    // concrete class: WordQuery defines all inherited pure virtual functions
    std::set<line_no> eval(const TextQuery &t) const {
        return t.run_query(query_word);
    }
    std::ostream& display(std::ostream &os) const {
        return os << query_word;
    }
    std::string query_word; // word for which to search
};

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

///////////////////////////////////////////////////////////////////////////////////
// class NotQuery
class NotQuery: public QueryBase
{
    friend Query operator~ (const Query &);
    NotQuery(const Query &q): query(q){}
    // concrete class: NotQuery defines all inherited pure virtual functions
    std::set<line_no> eval(const TextQuery&) const;
    std::ostream& display(std::ostream &os) const {
        return os << "~(" << query << ")";
    }
    const Query query;
};

///////////////////////////////////////////////////////////////////////////////////
// class BinaryQuery
class BinaryQuery: public QueryBase
{
protected:
    BinaryQuery(const Query &left, const Query &right, const std::string &op):
        lhs(left), rhs(right), oper(op) {}
    // abstract class: BinaryQuery doesn't define eval
    std::ostream& display(std::ostream &os) const {
        return os << "(" << lhs << " " << oper << " " << rhs << ")";
    }
    const Query lhs, rhs; 
    const std::string oper;
};

//////////////////////////////////////////////////////////////////////////////////////
// class AndQuery
class AndQuery: public BinaryQuery
{
    friend Query operator& (const Query&, const Query&);
    AndQuery(const Query &left, const Query &right): BinaryQuery(left, right, "&") {}
    // concrete class: AndQuery inherits display and defines remaining pure virtual

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

//////////////////////////////////////////////////////////////////////////////////////
// class OrQuery
class OrQuery: public BinaryQuery
{
    friend Query operator| (const Query&, const Query&);
    OrQuery(const Query &left, const Query &right): BinaryQuery(left, right, "|") {}
    // concrete class: OrQuery inherits display and defines remaining pure virtual
    std::set<line_no> eval(const TextQuery&) const;
};

////////////////////////////////////////////////////////////////////////////////////////
inline Query operator& (const Query &lhs, const Query &rhs)
{
    return new AndQuery(lhs, rhs);
}

inline Query operator| (const Query &lhs, const Query &rhs)
{
    return new OrQuery(lhs, rhs);
}

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

#endif

4. QueryAll.cpp

// Query.cpp

#include "QueryAll.h"
#include "TextQuery.h"
#include <map>
#include <algorithm>
using namespace std;

set<TextQuery::line_no> NotQuery::eval(const TextQuery &file) const
{
    // virtual call through the Query handle to eval
    set<line_no> has_val = query.eval(file);
    set<line_no> ret;
    // for each line in the input file, check whether that line is in has_val
    for (line_no n = 0; n != file.size(); ++n)
        if (has_val.find(n) == has_val.end())
            ret.insert(n);
    return ret;
}

set<TextQuery::line_no> AndQuery::eval(const TextQuery &file) const 
{
    // virtual calls through the Query handle to get result sets for operands
    set<line_no> left = lhs.eval(file);
    set<line_no> right = rhs.eval(file);
    set<line_no> ret;
    set_intersection(left.begin(), left.end(), right.begin(), right.end(), inserter(ret, ret.begin()));
    return ret;
}

set<TextQuery::line_no> OrQuery::eval(const TextQuery &file) const 
{
    // virtual calls through the Query handle to get result sets for operands
    set<line_no> right = rhs.eval(file);
    set<line_no> ret = lhs.eval(file);
    ret.insert(right.begin(), right.end());
    return ret;
}


4
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:567281次
    • 积分:7416
    • 等级:
    • 排名:第3263名
    • 原创:189篇
    • 转载:6篇
    • 译文:0篇
    • 评论:97条
    博客专栏
    文章分类
    最新评论