C++表达式解析(更新支持gcc)

        最近学习C++的字符串使用,突然想起了通过解析字符串实现计算任意表达式。C++主流的解析方式就是使用stack进行数据解析,无意间发现一篇通过递归的方式进行表达式解析的帖子,算法确实很赞 (原贴地址:【算法分享】纯VB解析四则运算文字表达式。支持任意个数括号嵌套 )那么动手吧,于是我按照作者的代码设计思路,移植成C++代码,使用VC6.0进行编译测试,效果良好。用到的知识点也不少,包含了STL的string、vector、sstream的对象使用,模板函数,递归算法使用等。有兴趣的朋友可以一起研究一下。

#pragma warning (disable: 4786) //屏蔽VC6下STL的报警 -_-b  
#include <math.h>  
#include <string>  
#include <algorithm>    //STL算法库头文件  
#include <sstream>  
#include <iostream>  
#include <vector>  
#include <iomanip>  
using namespace std;  
  
//宏定义,字符串转数值  
#define ATOF(str) atof((str).c_str())  
  
//转小写  
string ToLowerString(string str)  
{  
    transform(str.begin(), str.end(), str.begin(), (int (*)(int))tolower); 
   	return str;
}  
  
//转大写  
string ToUpperString(string str)  
{ 
    transform(str.begin(), str.end(), str.begin(), (int (*)(int))toupper); 
   	return str;
}  
  
//字符替换  
void string_Replace(string &str,const string &fstr,const string &rep)  
{  
    string::size_type pos = 0;  
    string::size_type a = fstr.length();  
    string::size_type b = rep.length();  
    if (b == 0)  
        while ((pos = str.find(fstr, pos)) != string::npos)  
        {  
            str.erase(pos, a);  
        }  
    else  
        while ((pos = str.find(fstr, pos)) != string::npos)  
        {  
            str.replace(pos, a, rep);  
            pos += b;  
        }  
}  
  
//字符串分隔  
vector<string> Split(const string str, const string pattern, int count = 0)  
{  
    vector<string> ret;  
    if (pattern.empty()) return ret;  
    size_t start = 0, index = str.find(pattern, 0);  
    int control = count;  
    while (index != str.npos && (count == 0 || (control--) > 1))  
    {  
        if (start != index)  
            ret.push_back(str.substr(start, index - start));  
        else  
            ret.push_back(string(""));  
        start = index + pattern.length();  
        index = str.find(pattern, start);  
    }  
    if (!str.substr(start).empty())  
        ret.push_back(str.substr(start));  
    else  
        for (int i = 0; i < count - ret.size(); i++)  
            ret.push_back(string(""));  
    return ret;  
}  
//判断是否为数值  
bool IsNumeric(const string& s)  
{  
    int lk = 0, rk = 0;  
  
    for (string::size_type i = 0; i < s.size(); i++)  
    {  
        if (s[i] == '(')  
        {  
            lk++;  
            continue;  
        }  
        if (s[i] == ')')  
        {  
            rk++;  
            continue;  
        }  
        if (s[i] == '.')  
            continue;  
        if (s[i] < '0' || s[i] > '9')  
        {  
            return false;  
        }  
    }  
    if (lk != rk) return false;  
    return true;  
}  
  
//符号判断  
int sgn(double x)  
{  
    int ret;  
    if (x > 0) ret = 1;  
    if (x < 0) ret = -1;  
    if (x == 0) ret = 0;  
    return ret;  
}  
  
//任意数值转换为string对象  
template<typename T>  
string toString(const T& t)  
{  
    ostringstream oss;  
    //设置转换精度  
    oss.setf(ios::fixed,ios::floatfield);  
    oss.precision(14);  
    oss << t;  
    return oss.str();  
}  
  
//字符串逆序  
string StrReverse(const string &ss)  
{  
    return string(ss.rbegin(),ss.rend()); //VS2010 支持反向迭代器构造函数,VC6不支持  
}  
  
double Eval(string s)  
{  
    double ret;  
    char op;  
    s = ToLowerString(s); //转为小写  
    string_Replace(s," ", ""); //去空格 
    string_Replace(s, "--", "+"); //负负为正 
    string_Replace(s, "mod", "%"); //取余数符号  
    string ss("(&-+%\\*/^"); //基础数学运算符 越靠后优先级高  
    string fc[] = {"Abs", "Atn", "Cos", "Exp", "Fix", "Int", "Log", "Rnd", "Sgn", "Sin", "Sqr", "Tan"};  
    for (int i = 0; i < sizeof(fc) / sizeof(fc[0]); i++)  
    {  
        vector<string> hs = Split(s, ToLowerString(fc[i]));  
        if (hs.size() == 2) //找到函数表达式  
        {  
            if ((IsNumeric(hs[1]) && hs[0].size() < 2) || (hs[0].empty() && hs[1].empty()))  
            {  
                string_Replace(hs[1], "(", "");  
                string_Replace(hs[1], ")", "");  
                switch (i)  
                {  
                case 0:  
                    ret = abs(ATOF(hs[1]));  
                    break;  
                case 1:  
                    ret = atan(ATOF(hs[1]));  
                    break;  
                case 2:  
                    ret = cos(ATOF(hs[1]));  
                    break;  
                case 3:  
                    ret = exp(ATOF(hs[1]));  
                    break;  
                case 4:  
                    ret = floor(ATOF(hs[1]));  
                    break;  
                case 5:  
                    ret = int(ATOF(hs[1]));  
                    break;  
                case 6:  
                    ret = log(ATOF(hs[1]));  
                    break;  
                case 7:  
                    ret = rand() * ATOF(hs[1]);  
                    break;  
                case 8:  
                    ret = sgn(ATOF(hs[1]));  
                    break;  
                case 9:  
                    ret = sin(ATOF(hs[1]));  
                    break;  
                case 10:  
                    ret = sqrt(ATOF(hs[1]));  
                    break;  
                case 11:  
                    ret = tan(ATOF(hs[1]));  
                    break;  
                default:  
                    break;  
                }  
                ret = ATOF(hs[0] + toString(ret));  
                cout << hs[0] << fc[i] << "(" << hs[1] << ")=" << ret << endl;  
                return ret;  
            }  
  
        }  
    }  
    if (IsNumeric(s) || s.empty())  
        ret = ATOF(s);  
    else  
        for (string::iterator it = ss.begin(); it != ss.end(); it++) //基础运算符解析  
        {  
            op = *it;  
            if (s.find(op, 0) != string::npos)  
            {  
                vector<string> fs = Split(StrReverse(s), toString(op), 2);  
                while (! IsNumeric(fs[1].substr(0, 1)) && (op == '-' || op == '+'))  
                {  
                    if (fs[1].find(op, 0) != string::npos)  
                    {  
                        vector<string> ms = Split(fs[1], toString(op), 2);  
                        fs[0] = fs[0] + op + ms[0];  
                        fs[1] = ms[1];  
                    }  
                    else  
                        op = '\0';  
                }  
                fs[0] = StrReverse(fs[0]);  
                fs[1] = StrReverse(fs[1]);  
                vector<string> ns = Split(fs[0], string(")"), 2);  
                switch (op)  
                {  
                case '(':  
                    cout << s << endl;  
                    ret = Eval(fs[1] + toString(Eval(ns[0])) + ns[1]);  
                    return ret;  
                    break;  
                case '&':  
                    ret = ATOF(toString(Eval(fs[1])) + toString(Eval(fs[0])));  
                    break;  
                case '+':  
                    ret = Eval(fs[1]) + Eval(fs[0]);  
                    break;  
                case '-':  
                    ret = Eval(fs[1]) - Eval(fs[0]);  
                    break;  
                case '*':  
                    ret = Eval(fs[1]) * Eval(fs[0]);  
                    break;  
                case '/':  
                    ret = Eval(fs[1]) / Eval(fs[0]);  
                    break;  
                case '\\':  
                    ret = int(Eval(fs[1]) / Eval(fs[0]));  
                    break;  
                case '%':  
                    ret = static_cast<int>(Eval(fs[1])) % static_cast<int>(Eval(fs[0]));  
                    break;  
                case '^':  
                    ret = pow(Eval(fs[1]), Eval(fs[0]));  
                    break;  
                }  
                if (op != '\0')  
                {  
                    cout << fs[1] << op << fs[0] << "=" << ret << endl;  
                    return ret;  
                }  
            }  
        }  
    return ret;  
}  
  
int main(int argc, char* argv[])  
{  
    //设置输出精度(全局有效)  
    cout<<setiosflags(ios::fixed)<<setprecision(10);  
    string ss = "235*(34-52/3)^2+sin(45*3.1415926/180)";  
    double ret = Eval(ss) ; 
    cout << ss << "=" << ret << endl;  
    return 0;  
}  


猜你喜欢

转载自blog.csdn.net/kingzhang2000/article/details/73526440