文本查询程序(C++primer 5th)可以输入语句的那种

1.本文所建立的代码是15章第9节的文本查询内容  希望大家可以看看功能基本实现

2.代码需求分析

进行文本查询 使用文件流对象进行文本解析

可以进行输入的逻辑语句 并进行解析      

  将对应的行进行打印

3.实现手段

进行文本解析进行智能指针保存 通过指针来进行保存和传递

再对不同的逻辑对象的分析提供面向对象的手段进行 接口实现

Ⅱ  对输入的表达式进行来分析 ,实现如四则运算类型的分析


第一个文件定义  QuerResult  和  Textresult  类 

进行的是按行打印  和对应的运行函数 rusnQueries

主要是通过  istringstream  来进行  行单词分解  保存  map<string,size_t> 中

文件的每一行使用  vector<string>保存  并使用  shared_ptr进行 动态保存

 
//QuerResult 和TextResult  此文件是  request.h  12.3节的内容就不详细介绍了
#ifndef REQUEST_H
#define REQUEST_H
#include<iostream>
#include<fstream>
#include<sstream>
#include<vector>
#include<set>
#include<map>
#include<string>
#include<memory>
#include<algorithm>
#include<iterator>
using std::cin;
using std::cout;
using std::shared_ptr;
using std::make_shared;
using std::vector;
using std::map;
using std::set;
using std::ifstream;
using std::string;
using std::istringstream;
//接收一个 ifstream对象  获得其文件流对象拷贝的指针和  对应单词的map
//返回QueryResult 的  query function
class QueryResult
{
public:
//这里与书上不同  因为在后续 类的设计中大量是分析所共享的指针  所以添加这些接口
	QueryResult(const string &s,const shared_ptr<vector<string>>f ,shared_ptr<set<size_t>> line):
		key_word(s),file_copy(f),line_no(line){}
	set<size_t>::iterator begin()   {return  line_no->begin(); }
	set<size_t>::iterator begin()   const  {return  line_no->begin(); }
	set<size_t>::iterator end()   {return  line_no->end(); }
	set<size_t>::iterator end()    const  {return  line_no->end(); }
	shared_ptr<vector<string>> get_file(){return file_copy;}
	shared_ptr<set<size_t>> line(){return  line_no;}
	size_t size() {return line_no->size();}
	string word() {return key_word;}
	~QueryResult(){}
private:
	string key_word;
	shared_ptr<vector<string>> file_copy;
	shared_ptr<set<size_t>> line_no;//对应的行号
};
class TextQuery
{   friend class QueryResult;
friend  void RunQueries(ifstream&);//打印结果的函数
public:
	TextQuery(ifstream&);
	QueryResult query(const string&) const ;
	~TextQuery(){}
private:
	shared_ptr<vector<string>> file;
	map<string ,shared_ptr<set<size_t> > > search;
};

TextQuery::TextQuery(ifstream& Query_file):file(new vector<string>)
{
	string line;
	while(getline(Query_file,line))
	{
		file->push_back(line);
		istringstream m(line);
		size_t n= file->size()-1;//行号从0开始
		string word;
		while(m>>word)  //进行单词分解
		{
			auto & lines=search[word];
			if(!lines)
				lines.reset(new set<size_t>);
			lines->insert(n);
		}
	}
}

QueryResult
	TextQuery::query(const string &key_word) const
{
	auto s= search.find(key_word);//使用at  会在没有此单词时产生  异常
	shared_ptr<set<size_t> > nodata( new set<size_t>);
	if(s!=search.end())
		return QueryResult(key_word,file,s->second);
	else return QueryResult(key_word,file,nodata);

}
//保存着 关键字   对应的文件指针  和 set<size_t>的指针

void RunQueries(ifstream&tq)
{
	TextQuery text(tq);
	cout<<"enther  the word to serach or q to quit";
	string s;
	if(cin>>s||s!="q")
	{
		auto mo= text.query(s);
		cout<<s<<"出现的了"<<mo.size()<<"次";
		for(auto i=mo.begin();i!=mo.end();++i)
		{
			  cout<<*i<<"行"<<(*mo.get_file())[*i]<<std::endl;
		}
	}

}
#endif // !REQUEST_H

这里主要使用面向对象的思想方法 进行 动态绑定   面对不同的对象 和运算符时  调用 不同的Query类型的eval查询操作

#ifndef REQUEST_H
#include"request.h"
#define REQUEST_H
//  此文件 Query和Query_base派生出的 Word_Query  Or_Quer Not_Query And_Query
//单个运算符对象使用 继承基类Query_base
//Query_base  有两个功能  1...eval执行对应的查询操作  接收一个TextQuery 返回Query_result
//2...rep()  通过调用eval对象获得匹配的QueryResult   打印自身的运算  即  Not_query 打印出 ~keyword;
class Query;
class Query_base
{    friend class Query;
protected:
	virtual~Query_base() {}

private:
	virtual QueryResult eval(const TextQuery&) const =0;
	virtual string rep () const =0;
};
//class  Query通过  重载运算符来实现不同的 保存指向Query_base的指针
class Query
{
	friend Query operator |(const Query&,const Query&);
	friend Query operator &(const Query&, const Query&);
	friend Query operator ~(const Query&);
public:
	Query() = default;
	Query(const string & sought);
	QueryResult eval(const TextQuery& t)const {return q->eval(t); }
	string rep() const {return q->rep();}
private:
	Query(shared_ptr<Query_base>query):q(query){}
	shared_ptr<Query_base> q;
};
std::ostream & operator<<(std::ostream &os,const Query &query)
{
	return os<<query.rep();
}
//与Query产生的对象  WordQuery
class WordQuery:public Query_base//如果缺少public标识符则为 private继承
{
	friend class Query;
	WordQuery(const string &t):sought(t){}
	QueryResult eval(const TextQuery&t1) const  { return t1.query(sought);}// error  out of range
	string rep() const {return sought;}
	string sought;
};
inline Query::Query(const string & t):q(new WordQuery (t)){}
//NotQuery是  形成独立的类所以  产生是另一个对象  所以为私有
//作用是利用指针产生动态绑定  1.. 定义自己的eval操作
//2...  rep() 函数在原来的基础上返回自己的运算符
class NotQuery: public Query_base
{
	friend Query operator ~(const Query&);
private:
	NotQuery( const Query&q):query(q){}
	QueryResult eval(const TextQuery&t)const ;
	string rep() const {return "~("+query.rep()+")";}
	Query query;
};
inline Query operator ~(const Query& t)
{
	return shared_ptr<Query_base>(new NotQuery(t));
}
//二元运算符的虚基类
class BinaryQuery :public Query_base
{
protected:
	//因为传入是const char[]   所以为 string  而不是string&
	BinaryQuery(const Query&l,string m,const Query&r):lhs(l),opSym(m),rhs(r){}
	//virtual QueryResult eval() const =0;  不定义eval
	//打印符号
	virtual string rep() const {return "("+lhs.rep()+" "+opSym+rhs.rep()+")";}
	Query lhs,rhs;//左右两个运算对象
	string opSym;//运算符
};
class AndQuery :public BinaryQuery
{
	friend Query operator &(const Query&,const Query&);
	AndQuery(const Query &left,const Query &right):BinaryQuery(left,"&",right){}
	QueryResult eval(const TextQuery& )const ;
	
};

inline Query operator &(const Query&r,const Query&t)
{
	//智能指针的参数应该是Query_base  指向基类对象
	return shared_ptr<Query_base>(new AndQuery(r,t));
}
class OrQuery:public BinaryQuery
{
	friend class QueryResult;
	friend Query operator |(const Query&,const Query&);
	OrQuery(const Query &left,const Query &right):BinaryQuery(left,"&",right){}
	QueryResult eval(const TextQuery& )const ;
	
};
inline Query operator |(const Query&r,const Query&t)
{
	return shared_ptr<Query_base>(new OrQuery(r,t));
}
//各eval 函数的定义
QueryResult
 NotQuery::eval(const TextQuery&t)const 
{
	auto result=query.eval(t);//获得QueryResult对象
	shared_ptr<set<size_t> >line_result(new set<size_t>);
	auto be=result.begin(); auto en=result.end();
	for(size_t n=0;n!=result.get_file()->size();++n)
	{
		//因为set是自动排序的所以  从零开始比较  如果不是加入到 line_result中去
		if(be==en||*be!=n)
			line_result->insert(n);
		else ++be;
	}
	return QueryResult(rep(),result.get_file(),line_result);
}
QueryResult
 OrQuery::eval(const TextQuery&t)const
{
	auto right=rhs.eval(t),left=lhs.eval(t);
	shared_ptr<set<size_t>> line_result(new set<size_t>);
	//并集
	line_result->insert(right.begin(),right.end());
	line_result->insert(left.begin(),left.end());
	//注意这里返回是自身的rep()符号显示操作
	return QueryResult(rep(),left.get_file(),line_result);
}
QueryResult
 AndQuery::eval(const TextQuery&t)const
{
	auto left=lhs.eval(t),right=rhs.eval(t);
	shared_ptr<set<size_t>> line_result(new set<size_t>);
	//交集
	for(auto a=left.begin(),b=right.end(); a!=left.end()&&b!=right.end() ; ++a,++b)
	{
		if(*a==*b) line_result->insert(*a);
	}
	//或者使用  标准算法的  来合并
	//std::_Set_intersection(left.begin(),left.end(),right.begin(),right.end(),std::(*line_result,line_result->begin()));
	return QueryResult(rep(),left.get_file(),line_result);
}
void print(QueryResult&result)
{
	
	cout<<result.word()<<"出现"<<result.line()->size()<<"次"<<std::endl;
	for(auto num:*result.line())
	{
		cout<<"line "<<num+1<<std::endl;//避免从0开始的行号产生错误
		cout<<(*(result.get_file()))[num]<<std::endl;
	}
}

//对于runQueries的改造 直接进行 打印 避免分析语句 
 此行代码是点击打开链接 这位仁兄提供的思路 
//有点偷懒  所以  我重新写了打印部分  实现逻辑语句的想法
void runQueries(ifstream& file)
{
	TextQuery tq(file);
	string s1,s2,s3;
	cout<<"请输入三个单词进行组合查询"<<std::endl;
	cin>>s1>>s2>>s3;
	Query Q1=Query (s1)&Query(s2)&Query(s3);
	Query Q2=Query (s1)|Query(s2)|Query(s3);
	Query Q3=Query (s1)|Query(s2)&Query(s3);
	Query Q4 = ~Query(s1);
	print(Q1.eval(tq));
	print(Q2.eval(tq));
	print(Q3.eval(tq));
	print(Q4.eval(tq));
}
#endif
此部分是进行逻辑运算语句的分析  同时 给出关于四则运算的解析方案进行对照
#include"Query_base.h"
#include<stack>
using std::stack;
//设计函数进行对于表达式解析
//进行改变成后缀表达式  进行类似的四则运算
unsigned int is_oper(const char c)
{
if ((c == '+ ') || (c == '- ')) return 2;
else if ((c == '* ') || (c == '/ ')) return 3;
else if ((c == '( ') || (c == ') ')) return 1;
else if (c >= '0'&&c <= '9') return 4;
else return 0;
}
unsigned int is_oper_string(string& c)
{
if ((c =="~")) return 2;
else if ((c == "&"||(c == "|"))) return 3;
else if ((c == "(") || (c == ")")) return 1;
else return 4;
}
//此处是四则运算转化为后缀表达式的 实现过程
string Mid_expresstion(stack<char>&rhs, string& s1)
{
string result;
for (auto &s : s1)
{
auto check = is_oper(s);//检查结果
if ((check == 4)){result.push_back(s); continue;}//数字直接进入表达式中
if (rhs.empty() ||s=='(') { rhs.push(s); continue;	}
if (s == ')') 
{
while (rhs.top()!='(')
{	result.push_back(rhs.top()); rhs.pop();}	
rhs.pop();//   ( 不保存
continue;
}
else 
{
/* 
若为 除括号外的其他运算符, 当其优先级高于除'('以外的栈顶运算符时,直接入栈。
否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,
直到一个比它优先级低的或者遇到了一个左括号为止。
*/
//error 错误deque iterator not dereferencable
while (check <=is_oper(rhs.top())&&(rhs.top()!='('))
{
  result.push_back(rhs.top()); rhs.pop();	
  if (rhs.empty()) break;
}  rhs.push(s);
}
}  
while (!rhs.empty())
{
result.push_back(rhs.top());
rhs.pop();
}  return result;
}
/*
例如在后缀表达式31+2*2/中: 
第一步遇到+ 计算结果 42*2/ 
第一步遇到* 计算结果 82/ 
第一步遇到/ 计算结果 4*/
//此次是四则运算的计算过程
double calculate(string &s)
{
	stack<double>ppx;
	double c = 0.0, b = 0.0, result = 0.0;
	for (unsigned int a =0; a <= s.size()-1; ++a)//将'/0'除去
	{
		if (s[a] >= '0'&&s[a] <= '9') 
		{
			ppx.push(s[a]-'0');
		}
		else
		{
			switch (s[a])
			{
			case '*': {c = ppx.top(); ppx.pop(); b = ppx.top(); ppx.pop();    result = c * b; ppx.push(result);  }break;
			case '+': {c = ppx.top(); ppx.pop(); b = ppx.top(); ppx.pop();    result = c + b; ppx.push(result);  }break;
			case '-': {c = ppx.top(); ppx.pop(); b = ppx.top(); ppx.pop();    result = b- c; ppx.push(result); } break;
			case '/': {c = ppx.top(); ppx.pop(); b = ppx.top(); ppx.pop();    result = b / c; ppx.push(result); } break;
			default:
				break;
			}
		}
	}return ppx.top();
}
//使用后缀表达式的方式进行逻辑表达进行解析
vector<string> Mid_expresstion_string(stack<string>&rhs,string &s)
{  //~ 2         & | 3         () 1    else  4
	istringstream ppx(s);
	string  word;
	vector<string> result;
	while (ppx >>word)
	{
		auto check = is_oper_string(word);//检查结果
		if ((check == 4)) { result.push_back(word); continue; }//单词直接进入表达式中
		if (rhs.empty() || word =="(") { rhs.push(word); continue; }
		if (word ==")")
		{
			while (rhs.top() != "(")
			{
				result.push_back(rhs.top()); rhs.pop();
			}
			rhs.pop();//   ( 不保存
			continue;
		}
		else 
		{
			/*
			若为 除括号外的其他运算符, 当其优先级高于除'('以外的栈顶运算符时,直接入栈。
			否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,
			直到一个比它优先级低的或者遇到了一个左括号为止。
			*/
			//error 错误deque iterator not dereferencable
			while (check <= is_oper_string(rhs.top()) && (rhs.top() != "("))
			{
				result.push_back(rhs.top()); rhs.pop();
				if (rhs.empty()) break;
			}  rhs.push(word);
		}
	} 
	while (!rhs.empty())
	{
		result.push_back(rhs.top());
		rhs.pop();
	}
	return result;
}
//逻辑语句的分析与四则运算类似  使用stack  来存储 生成的不同类型的Query
Query calculate_string(vector<string> &s)
{       //   ~ 2         & | 3         () 1    else  4
	stack<Query> ppx_text;
	Query c, b, result;
	for (unsigned int a = 0; a < s.size(); ++a)
	{
		auto brevity = is_oper_string(s[a]);
		if(brevity==4)  
		{
			ppx_text.push(Query(s[a]));
		}
		switch (brevity)
		{
		case 2: { b = ~Query(ppx_text.top());  ppx_text.pop(); ppx_text.push(b);  } break;
		case 3:     if (s[a] == "&")
		{
			b=Query(ppx_text.top());  ppx_text.pop();c= Query(ppx_text.top());  ppx_text.pop();
			ppx_text.push(c&b);
		}
					else
					{
						b = Query(ppx_text.top());  ppx_text.pop(); c = Query(ppx_text.top());  ppx_text.pop();
						ppx_text.push(c | b);
					}break;
		default:break;
		}
	
	}return ppx_text.top();
}
int main()
{	
//这里用的文件是  书上的文件
	ifstream in("storyDatafile");
	//runQueries(in);
	string s = "~ ( Alice  & ppx )";
	cout << "请输入需要的逻辑语句" << "如~ ( Alice  & ppx )" << "请打空格" << std::endl;
	std::getline(cin, s); //cin >> s;错误有空格  会导致字符串输入不完整
	stack<string>ppx;
	Query te1=calculate_string(  Mid_expresstion_string(ppx, s));
	print(te1.eval(in));
	system("pause");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值