类封装版表达式计算器
前些日子,写了个c语言的表达式计算器,感觉缺点很多,首先速度不够快,再来可复用性太差,难以移植到别的代码中,再就是兼容性不够,不好修改优化.。
这次我写了个c++ 版本的,封装成了类,类名是repre_calor,类定义文件叫repre_calor.h和 repre_calor.cpp,main.cpp是调用实验用的,如果在一个project里要用repre_calor的话,必须包含头文件repre_calor.h,然后把repre_calor.h和 repre_calor.cpp复制到project中,方可使用。
这次程序,栈利用了标准库中的stack类型,经测试,大大提高了速度和安全性,其他的c++标准化改动不列举了。。。。。。。呵呵。。。。。。
这是原先c语言版本http://www.cnblogs.com/huanyan/archive/2010/10/23/1858802.html
文件:repre_calor.h
#pragma once #ifndef REPRE_CALOR_H #define REPRE_CALOR_H #define ASCII_NUMBER_MAX 256 #include<vector> #include<stack> #include<string> class repre_calor { public: repre_calor() { state=false; input_error=false; brackets_error=false; calculation_error=false; wrong_brackets=false; ans=0.0; string_cursor=0; detail_error=false; importance.resize(ASCII_NUMBER_MAX,0); inim(importance); } bool state;//若true,则表明有错误发生 void error_output();//可以向用户输出具体发生了什么错误 bool work();//实际计算的成员函数 void initialize();//这个成员函数可以初始化表达式计算类 bool shuzi(std::string& ab);//判断字符串ab中的字符是否都是合法字符,合法返回0,否则返回1 bool kuohao(std::string& s);//判断字符串s中的左右括号个数是否匹配,匹配返回0,不匹配返回1 inline void inim(std::vector<int>& ck);//初始化合法字符列表ck void nospace(std::string& s);//去除字符串s中的空格 void input(std::istream& incoming);//调用这个成员函数从流incoming输入表达式 void input(std::string& incoming);//input另一个重载版本,支持用string类型重置pin double ans;//最后结果 bool detail_error;//若出错,是否输出详细错误信息?默认为输出(true) private: void calit(std::stack<double,std::vector<double> > &s1,std::stack<char,std::vector<char> > &s2,char tem); double change(std::string& s,std::string::size_type &st); bool input_error;//若输入非法字符,则为true bool brackets_error;//若括号不匹配,则为true bool calculation_error;//若表达式内出现非法计算单元,则为true bool wrong_brackets;//"()"这样的输入是不被允许的 std::string pin;//键盘输入 std::vector<int> importance;//优先级容器 std::stack<double,std::vector<double> > stack1;//stack1为操作数栈 std::stack<char,std::vector<char> > stack2;//stack2 为符号栈 char temp;/*stack2 为符号栈*/ std::string::size_type lenth,string_cursor; std::string calculation_error_infor; }; inline void repre_calor::inim(std::vector<int>& ck) { ck['+']=1; ck['-']=1; ck['*']=2; ck['^']=3; ck['/']=2; ck['(']=10; ck[')']=-1; ck['#']=-2; ck['a']=-3; ck[' ']=-3; ck['.']=-3; ck['1']=-3; ck['A']=-3; ck['2']=-3; ck['3']=-3; ck['7']=-3; ck['4']=-3; ck['8']=-3; ck['5']=-3; ck['9']=-3; ck['6']=-3; ck['0']=-3; } inline void repre_calor::input(std::istream& incoming) { std::getline(incoming,pin); } inline void repre_calor::input(std::string& incoming) { pin.assign(incoming); } #endif
文件:repre_calor.cpp
#ifndef REPRE_CALOR #define REPRE_CALOR #include <cstdlib> #include<iostream> #include <math.h> #include <conio.h> #include "repre_calor.h" double repre_calor::change(std::string &s,std::string::size_type &st) //从字符串s中读取一个数,st是在s上的游标 //即从st开始读出一个数,如果读不出来则返回0 { bool q(false); std::string::size_type temp; if ((s[st]=='-')&&(importance[s[(st)-1]]>(-3))) { q=true; ++st; } std::string tm(s,st,temp=s.find_first_not_of("1234567890.",st)); st=temp-1; if (q) return (-atof(tm.c_str())); else return(atof(tm.c_str())); } void repre_calor::calit(std::stack<double,std::vector<double> > &s1,std::stack<char,std::vector<char> > &s2,char tem)/*解析表达式*/ { for (; importance[s2.top()]>importance[tem]; s2.pop()) { if (s2.top()=='(') { return; } if (s1.empty()) { if (detail_error) std::cout<<"what you have input was wrong,input again"<<std::endl; input_error=true; state=true; return; } switch (s2.top()) { double temp_double; case '+': temp_double=s1.top(); s1.pop(); s1.top()+=temp_double; break; case '-': temp_double=s1.top(); s1.pop(); s1.top()-=temp_double; break; case '*': temp_double=s1.top(); s1.pop(); s1.top()*=temp_double; break; case '/': if (s1.top()==0.0) { if (detail_error)std::cout<<"0 is not a divisor,you must input again."<<std::endl; calculation_error=true; state=true; calculation_error_infor.assign("0 is not a divisor,you must input again."); return; } else { temp_double=s1.top(); s1.pop(); s1.top()/=temp_double; break; } case '^': temp_double=s1.top(); s1.pop(); if ((temp_double==0)&&(s1.top()==0)) { if (detail_error)std::cout<<"0^0 is not legal,input again"<<std::endl; calculation_error=true; state=true; calculation_error_infor.assign("0^0 is not legal,input again"); return; } s1.top()=pow(s1.top(),temp_double); break; } } } void repre_calor::nospace(std::string& s)/*去掉字符串中的空格*/ { std::string temp_s(s); std::string::size_type end_s(temp_s.size()); s.clear(); for (std::string::size_type si(0); si!=end_s; ++si) { if (temp_s[si]!=' ') { s.push_back(temp_s[si]); } } } bool repre_calor::kuohao(std::string& s)/*判断括号是否匹配,匹配返回0,不匹配返回1*/ { std::string::size_type len(s.size()),count(0),tem(0); if (s[count]=='(') ++tem; if (s[count]==')') --tem; if (tem<0) { brackets_error=true; state=true; return true; } ++count; for (; count!=len; ++count) { if (s[count]=='(') ++tem; if (s[count]==')') { if(s[count-1]=='(') { state=true; wrong_brackets=true; return true; } --tem; } if (tem<0) return true; } if (tem>0) return true; return false; } bool repre_calor::shuzi(std::string& ab)/*判断ab中存储的字符是否都是合法字符,合法返回0,否则返回1*/ { std::string::size_type temp_end(ab.size()); for (std::string::size_type i=0; i!=temp_end; ++i) { if (!importance[ab[i]]) { state=true; input_error=true; return true; } } return false; } bool repre_calor::work() { if (pin.empty()) { if (detail_error) std::cout<<"The class is empty,please give a string to .pin!!"<<std::endl; state=true; return true; } initialize(); stack2.push('#'); nospace(pin);/*先对pin中的表达式去除空格*/ lenth=pin.size()-1; if (shuzi(pin))/*shuzi(pin)判断pin中的表达式是否合法*/ { if (detail_error)std::cout<<std::endl<<"Not a right input,you must input again."<<std::endl; return true; } if (kuohao(pin))/*kuohao(pin)判断pin中的表达式中的括号是否能匹配*/ { if (detail_error)std::cout<<std::endl<<"you may lost a'(' or a ')',please input again"<<std::endl; return true; } if (pin[0]=='-') { if (pin[1]=='(') { stack2.push('-'); stack1.push(0); string_cursor=1; } else { ++string_cursor; stack1.push(-change(pin,string_cursor)); ++string_cursor; } } while (string_cursor<=lenth) { temp=pin[string_cursor]; if (((temp<='9')&&(temp>='0'))||(temp=='.')||((temp=='-')&&(importance[pin[string_cursor-1]]!=(-3)))) { stack1.push(change(pin,string_cursor)); } else { if ((temp=='a')||(temp=='A')) { stack1.push(ans); } else { if (importance[temp]>=importance[stack2.top()])/*判断运算符的优先级*/ /*如果当前操作的优先级高于之前操作的优先级,压栈*/ { stack2.push(temp); } else { calit(stack1,stack2,temp); if (state) return true; stack2.push(temp); if (temp==')') { stack2.pop(); stack2.pop(); } } } } ++string_cursor; } calit(stack1,stack2,'#'); if (state) return true; ans=stack1.top(); return false; } void repre_calor::initialize()//显式初始化 { inim(importance); while (!stack1.empty()) stack1.pop(); while (!stack2.empty()) stack2.pop(); string_cursor=0; lenth=0; state=false; input_error=false; brackets_error=false; calculation_error=false; wrong_brackets=false; } void repre_calor::error_output() { if (pin.empty()) { std::cout<<"No input!"<<std::endl; return; } if (!state) std::cout<<"No error was found!"<<std::endl; else { if (input_error) std::cout<<"Not a right input,you must input again."<<std::endl; if (wrong_brackets) std::cout<<"That '()' is not allowed!"<<std::endl; if (brackets_error) std::cout<<"You may lost a'(' or a ')',please input again"<<std::endl; if (calculation_error) std::cout<<calculation_error_infor<<std::endl; } } #endif
文件:main.cpp
#include <iostream> #include <conio.h> #include "repre_calor.h" int judgement('y'); void main_operation();//主界面 repre_calor calor;//定义calor为一个表达式的类 int main() { main_operation(); while ((judgement=='y')||(judgement=='Y')) { std::cout<<std::endl<<std::endl<<"Please input a representation"<<std::endl; calor.input(std::cin); calor.detail_error=false; if (calor.work()) calor.error_output();//原先计算全部过程精简为这一句 else std::cout<<"The answer is "<<calor.ans; std::cout<<"\nContinue(y/n)?"; judgement=_getch(); while ((judgement!='y')&&(judgement!='Y') &&(judgement!='n')&&(judgement!='N')) { std::cout<<std::endl<<"You need to input again."<<std::endl; judgement=_getch(); } } std::cout<<std::endl<<"***********************************"<<std::endl <<"May you have a good time!!\nBye bye!!"<<std::endl <<"***********************************"<<std::endl; system("pause"); return 0; }