C++实现简单计算器(字符串替换)


本文介绍了一种使用字符串替换的方法来计算数学表达式的值。相对于使用栈的方式,这种方法效率较低。这种计算器支持带括号的四则运算。

仅支持四则运算和括号的计算器

这部分代码实现了一个简单的计算器,它可以处理带有括号的四则运算表达式,并输出正确的计算结果;如果表达式输入有误或出现了分母为零等情况将返回nan。代码如下:

#include <string>
#include <vector>
#include <math.h>
using namespace std;
// 仅支持四则运算的计算器
double _cal(string s)
{
    string s1;
    string::iterator a, b, i; // a记录'(',b记录')'
    string::size_type n = 0;
    int l;
    if (false)
    F:
        s.replace(a, i + 1, to_string(_cal(string(a + 1, i))).c_str()); // 递归计算括号
R:
    i = s.begin();
    while (i < s.end())
    {
        if (*i == ' ' || *i == '\t')
        {
            s.erase(i);
            goto R;
        }
        if (*i == '(')
        {
            if (!n++)
                a = i;
        }
        else if (*i == ')')
        {
            if (!--n)
                goto F;
        }
        else if (*i != '\0' && *i != '.' && *i != 'e' && *i != '*' && *i != '-' && *i != '+' && *i != '/' && (*i < '0' || *i > '9') || (*i == '/' && *(i + 1) == '0' && *(i + 2) != '.'))
            return NAN; // 不是数学表达式
        ++i;
    }
    if (n)
        return NAN; // 左括号个数不等于右括号个数
    vector<string::size_type> u;
    /* k用作bool数组
     * 第一位表示第一个数字的正负性
     * 第二位表示第二个数字的正负性
     * 第三位表示第一个数字是否为字符串首个数字
     */
    unsigned char k('\0');
    // 计算乘除
    for (b = a = s.begin(); a < s.end(); ++a)
        if (*a == '*' || *a == '/')
            u.push_back(a - b);
    while (u.size())
    {
        i = a = b = s.begin() + u[0];
        while ((*--b >= '0' && *b <= '9') || *b == '.' || *b == 'e')
            if (b == s.begin())
            {
                k = 4;
                goto G;
            }
        // n记录第一个数字的首位的位置
        k += *b == '-';
        if (*b == '-')
            n = b - s.begin();
        else
            n = ++b - s.begin();
    G:
        double t = stod(string(b, a++));
        do
            if (++a == s.end())
                break;
        while ((*a >= '0' && *a <= '9') || *a == '.' || *a == 'e');
        double w = stod(string(i + 1, a));
        k += (w < 0) * 2;
        if (*i == '*')
        {
            l = (s1 = to_string(t * w)).size() - (a - b);
            s.replace(b, a, s1.c_str());
        }
        else if (w)
        {
            l = (s1 = to_string(t / w)).size() - (a - b);
            s.replace(b, a, s1.c_str());
        }
        else
            return NAN; // 除数为0
        switch (k)
        {
        case 2:
            s.erase(s.begin() + n - 1);
            break; // 删除-号前的+
        case 3:
            s.insert(s.begin() + n, '+'); // 在计算结果之前加一个+
        }
        u.erase(u.begin());
        for (auto &q : u)
            q += l;
    }
    // 计算加减
H:
    for (a = (b = s.begin()) + 1; a < s.end(); ++a)
        if (*a == '+')
        {
            if (*(a + 1) == '-' || *(a + 1) == '+')
            {
                s.erase(a);
                goto H;
            }
            u.push_back(a - b);
        }
        else if (*a == '-')
        {
            if (*(a + 1) == '-')
            {
                s.replace(a, a + 2, "+");
                goto H;
            }
            else if (*(a + 1) == '+')
            {
                s.erase(a + 1);
                goto H;
            }
            u.push_back(a - b);
        }
        else if(*a=='e'||*a=='E')
            if(*(a+1)=='-')
                ++a;
    while (u.size())
    {
        i = a = (b = s.begin()) + u[0];
        double t = stod(string(b, a++));
        do
            if (++a == s.end())
                break;
        while ((*a >= '0' && *a <= '9') || *a == '.' || *a == 'e');
        if (*i++ == '+')
            l = (s1 = to_string(t + stod(string(i, a)))).size() - (a - b);
        else
            l = (s1 = to_string(t - stod(string(i, a)))).size() - (a - b);
        s.replace(b, a, s1.c_str());
        u.erase(u.begin());
        for (auto &q : u)
            q += l;
    }
    return stod(s);
}

支持部分常用函数的计算器

实际使用中,我们可能会遇到诸如sinexplog等函数,这部分代码在基础计算器的基础上添加了对这些函数的支持。

/*
 * 计算器
 * 计算字符串s代表的值
 * 支持的函数:sqrt,sin,log,exp,pow,abs,cos,tan,asin,acos,atan
 * 支持无理数pi,但不支持e(e已经用作科学计数法的表示),可以用exp(1)表示e
 */
double calStr(string s)
{
    if(s.empty())return 0;
    string::iterator i(s.begin());
    do
        switch (*i)
        {
        case 's':
        {
            string::iterator j(i);
            if (*++j == 'i')
            {
                if (*++j != 'n')
                    return NAN;
                if (*++j != '(')
                    return NAN;
                string::iterator k(++j);
                string::size_type n = 1;
                if (*k == '(')
                    ++n;
                else if (*k == ')')
                    return NAN;
                while (++k != s.end())
                    switch (*k)
                    {
                    case '(':
                        ++n;
                        break;
                    case ')':
                        if (!--n)
                            return calStr(s.replace(i, k + 1, to_string(sin(calStr(string(j, k))))));
                    }
                return NAN;
            }
            if (*j != 'q')
                return NAN;
            if (*++j != 'r')
                return NAN;
            if (*++j != 't')
                return NAN;
            if (*++j != '(')
                return NAN;
            string::iterator k(++j);
            string::size_type n = 1;
            if (*k == '(')
                ++n;
            else if (*k == ')')
                return NAN;
            while (++k != s.end())
                switch (*k)
                {
                case '(':
                    ++n;
                    break;
                case ')':
                    if (!--n)
                        return calStr(s.replace(i, k + 1, to_string(sqrt(calStr(string(j, k))))));
                }
            return NAN;
        }
        case 'l':
        {
            string::iterator j(i);
            if (*++j != 'o')
                return NAN;
            if (*++j != 'g')
                return NAN;
            if (*++j != '(')
                return NAN;
            string::iterator k(++j);
            string::size_type n = 1;
            if (*k == '(')
                ++n;
            else if (*k == ')')
                return NAN;
            while (++k != s.end())
                switch (*k)
                {
                case '(':
                    ++n;
                    break;
                case ')':
                    if (!--n)
                        return calStr(s.replace(i, k + 1, to_string(log(calStr(string(j, k))))));
                }
            return NAN;
        }
        case 'e':
        {
            string::iterator j(i);
            if (*++j != 'x')
                continue;
            if (*++j != 'p')
                return NAN;
            if (*++j != '(')
                return NAN;
            string::iterator k(++j);
            string::size_type n = 1;
            if (*k == '(')
                ++n;
            else if (*k == ')')
                return NAN;
            while (++k != s.end())
                switch (*k)
                {
                case '(':
                    ++n;
                    break;
                case ')':
                    if (!--n)
                        return calStr(s.replace(i, k + 1, to_string(exp(calStr(string(j, k))))));
                }
            return NAN;
        }
        case 'p':
        {
            string::iterator j(i);
            if (*++j != 'o')
            {
                if (*j == 'i')
                    return calStr(s.replace(i, ++j, "3.1415926535897932384626433832795"));
                return NAN;
            }
            if (*++j != 'w')
                return NAN;
            if (*++j != '(')
                return NAN;
            string::iterator k(++j), x;
            string::size_type n = 1;
            if (*k == '(')
                ++n;
            else if (*k == ')')
                return NAN;
            while (++k != s.end())
                switch (*k)
                {
                case ',':
                    x = k;
                    break;
                case '(':
                    ++n;
                    break;
                case ')':
                    if (!--n)
                        return calStr(s.replace(i, k + 1, to_string(pow(calStr(string(j, x)), calStr(string(x + 1, k))))));
                }
            return NAN;
        }
        case 'c':
        {
            string::iterator j(i);
            if (*++j != 'o')
                return NAN;
            if (*++j != 's')
                return NAN;
            if (*++j != '(')
                return NAN;
            string::iterator k(++j);
            string::size_type n = 1;
            if (*k == '(')
                ++n;
            else if (*k == ')')
                return NAN;
            while (++k != s.end())
                switch (*k)
                {
                case '(':
                    ++n;
                    break;
                case ')':
                    if (!--n)
                        return calStr(s.replace(i, k + 1, to_string(cos(calStr(string(j, k))))));
                }
            return NAN;
        }
        case 't':
        {
            string::iterator j(i);
            if (*++j != 'a')
                return NAN;
            if (*++j != 'n')
                return NAN;
            if (*++j != '(')
                return NAN;
            string::iterator k(++j);
            string::size_type n = 1;
            if (*k == '(')
                ++n;
            else if (*k == ')')
                return NAN;
            while (++k != s.end())
                switch (*k)
                {
                case '(':
                    ++n;
                    break;
                case ')':
                    if (!--n)
                        return calStr(s.replace(i, k + 1, to_string(tan(calStr(string(j, k))))));
                }
            return NAN;
        }
        case 'a':
        {
            string::iterator j(i);
            switch (*++j)
            {
            case 's':
            {
                if (*++j != 'i')
                    return NAN;
                if (*++j != 'n')
                    return NAN;
                if (*++j != '(')
                    return NAN;
                string::iterator k(++j);
                string::size_type n = 1;
                if (*k == '(')
                    ++n;
                else if (*k == ')')
                    return NAN;
                while (++k != s.end())
                    switch (*k)
                    {
                    case '(':
                        ++n;
                        break;
                    case ')':
                        if (!--n)
                            return calStr(s.replace(i, k + 1, to_string(asin(calStr(string(j, k))))));
                    }
                return NAN;
            }
            case 'c':
            {
                if (*++j != 'o')
                    return NAN;
                if (*++j != 's')
                    return NAN;
                if (*++j != '(')
                    return NAN;
                string::iterator k(++j);
                string::size_type n = 1;
                if (*k == '(')
                    ++n;
                else if (*k == ')')
                    return NAN;
                while (++k != s.end())
                    switch (*k)
                    {
                    case '(':
                        ++n;
                        break;
                    case ')':
                        if (!--n)
                            return calStr(s.replace(i, k + 1, to_string(acos(calStr(string(j, k))))));
                    }
                return NAN;
            }
            case 't':
            {
                if (*++j != 'a')
                    return NAN;
                if (*++j != 'n')
                    return NAN;
                if (*++j != '(')
                    return NAN;
                string::iterator k(++j);
                string::size_type n = 1;
                if (*k == '(')
                    ++n;
                else if (*k == ')')
                    return NAN;
                while (++k != s.end())
                    switch (*k)
                    {
                    case '(':
                        ++n;
                        break;
                    case ')':
                        if (!--n)
                            return calStr(s.replace(i, k + 1, to_string(atan(calStr(string(j, k))))));
                    }
                return NAN;
            }
            }
            if (*j != 'b')
                return NAN;
            if (*++j != 's')
                return NAN;
            if (*++j != '(')
                return NAN;
            string::iterator k(++j);
            string::size_type n = 1;
            if (*k == '(')
                ++n;
            else if (*k == ')')
                return NAN;
            while (++k != s.end())
                switch (*k)
                {
                case '(':
                    ++n;
                    break;
                case ')':
                    if (!--n)
                        return calStr(s.replace(i, k + 1, to_string(abs(calStr(string(j, k))))));
                }
            return NAN;
        }
        }
    while (++i != s.end());
    return _cal(s);
}

支持带未知数的函数表达式

若表达式中包含未知数x,可以使用如下函数来计算:

//在表达式中带有x
double calStr_x(string s,const double& x)
{
    for(auto p(s.begin());p!=s.end();++p)
        if(*p=='x')
            if(p==s.begin()||p+1==s.end()||*(p-1)!='e'||*(p+1)!='p')
                return calStr_x(s.replace(p,p+1,to_string(x)),x);
    return calStr(s);
}
  • 16
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zsc_118

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值