类封装版表达式计算器

        前些日子,写了个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;
}
posted @ 2010-10-23 00:34  幻魇  阅读(319)  评论(0编辑  收藏  举报