15.9 文本查询程序再探(继承)

通过类的继承和组合,本文档详细介绍了如何重写一个文本查询程序,支持与、或、非等复杂查询策略。利用Query类及其基类Query_base,结合BinaryQuery抽象基类,实现了AndQuery和OrQuery双目查询策略,以及NotQuery的取非策略。

本节中使用类的继承方式重写了文本查询程序,支持多种查询策略:或,与,非。
类继承关系
其中Query是提供给用户使用的类,含有两个接口:evalrepeval用于查找对应的单词出现的文本,rep用于输出用户指定的查询内容。
Query_base是抽象基类,WordQuery是普通查询策略,NotQuery是取非查询策略。对于双目查询策略,定义了一个新的抽象基类BinaryQueryAndQueryOrQuery是继承于它的两个与/非查询策略。

对于用户的查询来说,一个典型表达式:
查询表达式
用户代码:
main.cpp

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include "Query.h"
#include "TextQuery.h"
#include "QueryResult.h"

using namespace std;

int main(int argc, char **argv) {
   ifstream f("test.txt");
   if (f) {
      TextQuery t(f);
      Query q = Query("whilst") & Query("the");
      cout << q.rep() << endl;
      QueryResult answer = q.eval(t);
      print(cout, answer);
   }
   else {
      cout << "Cannot open file" << endl;
      exit(1);
   }

   return 0;
}

源文本:

Oscar Fingal O'Flahertie Wills Wilde (16 October 1854 to 30 November 1900) was an Irish writer, poet, and prominent aesthete who, after writing in different forms throughout the 1880s, became one of London's most popular playwrights in the early 1890s. Today he is remembered for his epigrams, plays and the tragedy of his imprisonment, followed by his early death.
Wilde's parents were successful Dublin intellectuals and from an early age he was tutored at home, where he showed his intelligence, becoming fluent in French and German. He attended boarding school for six years, then matriculated to university at seventeen years of age. Reading Greats, Wilde proved himself to be an outstanding classicist, first at Dublin, then at Oxford. His intellectual horizons were broad: he was deeply interested in the rising philosophy of aestheticism (led by two of his tutors, Walter Pater and John Ruskin) though he also profoundly explored Roman Catholicism and finally converted on his deathbed.
After university Wilde moved to London, into fashionable cultural and social circles. As a spokesman for aestheticism, he tried his hand at various literary activities; he published a book of poems, lectured America and Canada on the new "English Renaissance in Art" and then returned to London to work prolifically as a journalist for four years. Known for his biting wit, flamboyant dress, and glittering conversation, Wilde was one of the best known personalities of his day. At the turn of the 1890s, he refined his ideas about the supremacy of art in a series of dialogues and essays; though it was his only novel, The Picture of Dorian Gray, which began a more lasting oeuvre. The opportunity to construct aesthetic details precisely, combined with larger social themes, drew Wilde to writing drama. He wrote Salome in French in Paris in 1891, but it was refused a licence. Unperturbed, Wilde produced four society comedies in the early 1890s, which made him one of the most successful playwrights of late Victorian London.
At the height of his fame and success, whilst his masterpiece, The Importance of Being Earnest, was still on stage in London, Wilde sued his lover's father for libel. After a series of trials, Wilde was convicted of gross indecency with other men and imprisoned for two years, held to hard labour. In prison he wrote De Profundis, a long letter which discusses his spiritual journey through his trials, forming a dark counterpoint to his earlier philosophy of pleasure. Upon his release he left immediately for France, never to return to Ireland or Britain. There he wrote his last work, The Ballad of Reading Gaol, a long poem commemorating the harsh rhythms of prison life. He died destitute in Paris at the age of forty-six

Query.h

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

class Query {
    friend Query operator~(const Query &q);
    friend Query operator&(const Query &lhs, const Query &rhs);
    friend Query operator|(const Query &lhs, const Query &rhs);
    friend ostream &operator<<(ostream &os, const Query &q);
public:
    Query(const std::string &);
    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 "stdafx.h"
#include "Query.h"
#include "WordQuery.h"
#include "BinaryQuery.h"
#include "AndQuery.h"
#include "OrQuery.h"
#include "NotQuery.h"
#include "QueryResult.h"

Query operator~(const Query &q) {
    return std::shared_ptr<Query_base>(new NotQuery(q));
}

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

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

std::ostream &operator<<(std::ostream &os, const Query &q) {
    //print(os, q->eval(const TextQuery &t));
    os << q.rep() << endl;
    return os;
}

Query::Query(const std::string &s)
    : q(std::shared_ptr<Query_base>(new WordQuery(s))) {}

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

std::string Query::rep() const {
    return q->rep();
}

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

Query_base.h

#pragma once
#include "TextQuery.h"
#include "QueryResult.h"

class Query_base {
    friend class Query;
protected:
    using line_no = TextQuery::line_no;
    virtual ~Query_base() {};
private:
    virtual QueryResult eval(const TextQuery &t) const = 0;
    virtual std::string rep() const = 0;
};

BinaryQuery.h

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

class BinaryQuery : public Query_base {
protected:
    BinaryQuery(const Query &lhs, const Query &rhs, const std::string &s);
    virtual std::string rep() const override;
    Query lhs, rhs;
    std::string ops;
};

BinaryQuery.cpp

#include "stdafx.h"
#include "BinaryQuery.h"

BinaryQuery::BinaryQuery(const Query &lhs, const Query &rhs, const std::string &s)
    : lhs(lhs), rhs(rhs), ops(s) {}

std::string BinaryQuery::rep() const {
    return ops;
}

WordQuery.h

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

class WordQuery : public Query_base {
    friend class Query;
private:
    WordQuery(const std::string &s);
    virtual QueryResult eval(const TextQuery &t) const override;
    virtual std::string rep() const override;
    std::string query_word;
};

WordQuery.cpp

#include "stdafx.h"
#include "WordQuery.h"

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

QueryResult WordQuery::eval(const TextQuery &t) const {
    return t.query(query_word);
}

std::string WordQuery::rep() const {
    return query_word;
}

NotQuery.h

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

class NotQuery : public Query_base {
    friend Query operator~(const Query &q);
private:
    NotQuery(const Query &q);
    virtual QueryResult eval(const TextQuery &t) const override;
    virtual std::string rep() const override;
    Query query;
};

NotQuery.cpp

#include "stdafx.h"
#include "NotQuery.h"

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

QueryResult NotQuery::eval(const TextQuery &t) const {
    auto result = t.query(query.rep());
    auto beg = result.get_begin();
    auto end = result.get_end();
    auto file = result.get_file();
    size_t size= file->size();
    auto ret_lines = std::make_shared<set<TextQuery::line_no>>();
    if (beg == end) {
        for (size_t i = 0; i < size; ++i) {
            ret_lines->insert(i);
        }
    } else {
        while (beg != end) {
            for (size_t i = 0; i < size; ++i) {
                if (*beg != i) {
                    ret_lines->insert(i);
                }
            }
            ++beg;
        }
    }
    return QueryResult(rep(), file, ret_lines);
}

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

AndQuery.h

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

class AndQuery : public BinaryQuery {
    friend Query operator&(const Query &, const Query &);
    AndQuery(const Query &lhs, const Query &rhs);
    virtual QueryResult eval(const TextQuery &t) const override;
};

AndQuery.cpp

#include "stdafx.h"
#include "AndQuery.h"
#include <algorithm>
#include <iterator>

AndQuery::AndQuery(const Query &lhs, const Query &rhs)
    : BinaryQuery(lhs, rhs, "&") {}

QueryResult AndQuery::eval(const TextQuery &t) const {
    auto left = lhs.eval(t);
    auto right = rhs.eval(t);
    auto ret_lines = std::make_shared<set<TextQuery::line_no>>();
    std::set_intersection(left.get_begin(), left.get_end(),
                          right.get_begin(), right.get_end(),
                          inserter(*ret_lines, ret_lines->begin()));
    return QueryResult(lhs.rep() + "&" + rhs.rep(), left.get_file(), ret_lines);
}

OrQuery.h

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

class OrQuery : public BinaryQuery {
    friend Query operator|(const Query &, const Query &);
    OrQuery(const Query &lhs, const Query &rhs);
    virtual QueryResult eval(const TextQuery &t) const override;
};

OrQuery.cpp

#include "stdafx.h"
#include "OrQuery.h"

OrQuery::OrQuery(const Query &lhs, const Query &rhs)
    : BinaryQuery(lhs, rhs, "|") {}

QueryResult OrQuery::eval(const TextQuery &t) const {
    auto left = lhs.eval(t);
    auto right = rhs.eval(t);
    auto ret_lines = std::make_shared<set<TextQuery::line_no>>(left.get_begin(),left.get_end());
    ret_lines->insert(right.get_begin(), right.get_end());
    return QueryResult(lhs.rep() + "|" + rhs.rep(), left.get_file(), ret_lines);
}

TextQuery.h

#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include "QueryResult.h"

using namespace std;

class QueryResult;

class TextQuery {
public:
    using line_no = vector<string>::size_type;
    TextQuery(ifstream &f);
    QueryResult query(const string &s) const;
private:
    map<string, shared_ptr<set<line_no>>> m_vm;
    shared_ptr<vector<string>> m_text;
};

TextQuery.cpp

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

TextQuery::TextQuery(ifstream &f)
    : m_text(new vector<string>) {
    string tmp;
    line_no pos = 1;
    while (getline(f, tmp)) {
        m_text->push_back(tmp);
        stringstream line(tmp);
        string word;
        while (line >> word) {
            auto &lines = m_vm[word];
            if (!lines) {
                lines.reset(new set<line_no>);
            }
            lines->insert(pos);
        }
        ++pos;
    }
}

QueryResult TextQuery::query(const string &s) const {
    shared_ptr<set<line_no>> nodata(new set<line_no>());
    auto itr = m_vm.find(s);
    if (itr == m_vm.end()) {
        return QueryResult(s, m_text, nodata);
    } else {
        return QueryResult(s, m_text, itr->second);
    }
}

QueryResult.h

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

using namespace std;

class QueryResult {
    friend void print(std::ostream &os, const QueryResult &q);
public:
    using line_no = vector<string>::size_type;
    QueryResult(const string target, shared_ptr<vector<string>> sv, shared_ptr<set<line_no>> sl);
    set<line_no>::const_iterator get_begin() const;
    set<line_no>::const_iterator get_end() const;
    shared_ptr<vector<string>> get_file() const;
private:
    string m_target;
    shared_ptr<vector<string>> m_text;
    shared_ptr<set<line_no>> m_lines;
};

QueryResult.cpp

#include "stdafx.h"
#include "QueryResult.h"

void print(std::ostream &os, const QueryResult &q) {
    os << "The word: " << q.m_target << endl;
    os << "Occur at line: " << endl;
    size_t index = 0;
    for (const auto i:*q.m_lines) {
        os << i << " with string: " << (*q.m_text)[index] << endl;
        ++index;
    }
}

QueryResult::QueryResult(const string target, shared_ptr<vector<string>> text, shared_ptr<set<TextQuery::line_no>> lines)
    : m_target(target), m_text(text), m_lines(lines) {}

set<TextQuery::line_no>::const_iterator QueryResult::get_begin() const {
    return m_lines->cbegin();
}

set<TextQuery::line_no>::const_iterator QueryResult::get_end() const {
    return m_lines->cend();
}

shared_ptr<vector<string>> QueryResult::get_file() const {
    return m_text;
}

Result:
查询whilst和the同时出现的行

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值