在C++中从字符串中计算算术表达式

Mah*_*asi 47 c++

我正在寻找一种简单的方法来从字符串中评估一个简单的数学表达式,如下所示:

3*2 + 4*1 +(4 + 9)*6

我只想要+*操作加号()标志.并且*优先于+.

Hen*_*rik 31

我想你正在寻找一个简单的递归下降解析器.

这是一个非常简单的例子:

const char * expressionToParse = "3*2+4*1+(4+9)*6";

char peek()
{
    return *expressionToParse;
}

char get()
{
    return *expressionToParse++;
}

int expression();

int number()
{
    int result = get() - '0';
    while (peek() >= '0' && peek() <= '9')
    {
        result = 10*result + get() - '0';
    }
    return result;
}

int factor()
{
    if (peek() >= '0' && peek() <= '9')
        return number();
    else if (peek() == '(')
    {
        get(); // '('
        int result = expression();
        get(); // ')'
        return result;
    }
    else if (peek() == '-')
    {
        get();
        return -factor();
    }
    return 0; // error
}

int term()
{
    int result = factor();
    while (peek() == '*' || peek() == '/')
        if (get() == '*')
            result *= factor();
        else
            result /= factor();
    return result;
}

int expression()
{
    int result = term();
    while (peek() == '+' || peek() == '-')
        if (get() == '+')
            result += term();
        else
            result -= term();
    return result;
}

int _tmain(int argc, _TCHAR* argv[])
{

    int result = expression();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 3年后 - 抱歉僵尸! - 此代码中有一个BUG.将表达式"-1 + 2"传递给它得到结果-3.要解决这个问题,在"factor()"函数中,位处理(peek()==' - ')需要返回factor(),而不是expression(). (7认同)
  • 我不认为递归正确对算术有好处,因为它完全是左递归的. (3认同)

Mon*_*nir 31

可以尝试:http://partow.net/programming/exprtk/index.html

  1. 非常简单
  2. 只需在您的源代码中包含"exprtk.hpp"即可.
  3. 您可以动态更改表达式变量的值.
  4. 良好的起点:http://partow.net/programming/exprtk/code/exprtk_simple_example_01.cpp

  • 这应该是公认的答案!`exprtk`非常强大而简单,值先尝试! (14认同)
  • @mLstudent33:*“只需要在源代码中包含“exprtk.hpp”。”* (2认同)

Isa*_*acH 11

只是为了添加另一种选择,请考虑尝试TinyExpr来解决这个问题.它是一个源代码文件中的开源和自包含.它实际上是用C语言编写的,但根据我的经验,它会像C++一样干净地编译.

从上面解决您的示例表达式非常简单:

#include "tinyexpr.h"
#include <stdio.h>

int main()
{
    double answer = te_interp("3*2+4*1+(4+9)*6", 0);
    printf("Answer is %f\n", answer);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


Mus*_*dız 5

所以我正在寻找这个问题的答案。我正在尝试创建自己的编程语言。对于数学表达式,我需要该函数。

好吧,我给你。按照您想要的方式使用它。

/* Code here before is useless now */
Run Code Online (Sandbox Code Playgroud)

这是完成此类任务的一种漫长且可能效率低下的方式。但它可以完成工作,所以继续吧。很快我就计划添加变量支持。但你也可以做到,这很简单(我想:P)。

编辑:我刚刚整理了这个功能,现在它就像魔术一样工作 XD..

using namespace std;

double eval(string expr)
{
    string xxx; // Get Rid of Spaces
    for (int i = 0; i < expr.length(); i++)
    {
        if (expr[i] != ' ')
        {
            xxx += expr[i];
        }
    }

    string tok = ""; // Do parantheses first
    for (int i = 0; i < xxx.length(); i++)
    {
        if (xxx[i] == '(')
        {
            int iter = 1;
            string token;
            i++;
            while (true)
            {
                if (xxx[i] == '(')
                {
                    iter++;
                } else if (xxx[i] == ')')
                {
                    iter--;
                    if (iter == 0)
                    {
                        i++;
                        break;
                    }
                }
                token += xxx[i];
                i++;
            }
            //cout << "(" << token << ")" << " == " << to_string(eval(token)) <<  endl;
            tok += to_string(eval(token));
        }
        tok += xxx[i];
    }

    for (int i = 0; i < tok.length(); i++)
    {
        if (tok[i] == '+')
        {
            //cout << tok.substr(0, i) + " + " +  tok.substr(i+1, tok.length()-i-1) << " == " << eval(tok.substr(0, i)) + eval(tok.substr(i+1, tok.length()-i-1)) << endl;
            return eval(tok.substr(0, i)) + eval(tok.substr(i+1, tok.length()-i-1));
        } else if (tok[i] == '-')
        {
            //cout << tok.substr(0, i) + " - " +  tok.substr(i+1, tok.length()-i-1) << " == " << eval(tok.substr(0, i)) - eval(tok.substr(i+1, tok.length()-i-1)) << endl;
            return eval(tok.substr(0, i)) - eval(tok.substr(i+1, tok.length()-i-1));
        }
    }

    for (int i = 0; i < tok.length(); i++)
    {
        if (tok[i] == '*')
        {
            //cout << tok.substr(0, i) + " * " +  tok.substr(i+1, tok.length()-i-1) << " == " << eval(tok.substr(0, i)) * eval(tok.substr(i+1, tok.length()-i-1)) << endl;
            return eval(tok.substr(0, i)) * eval(tok.substr(i+1, tok.length()-i-1));
        } else if (tok[i] == '/')
        {
            //cout << tok.substr(0, i) + " / " +  tok.substr(i+1, tok.length()-i-1) << " == " << eval(tok.substr(0, i)) / eval(tok.substr(i+1, tok.length()-i-1)) << endl;
            return eval(tok.substr(0, i)) / eval(tok.substr(i+1, tok.length()-i-1));
        }
    }

    //cout << stod(tok.c_str()) << endl;
    return stod(tok.c_str()); // Return the value...
}
Run Code Online (Sandbox Code Playgroud)

  • 此代码不适用于负数。这破坏了操作顺序和功能。我通过添加一个简单的规则来修复这个 `else if (tok[i] == '-') { if (tok.substr(0, i).length() != 0 &amp;&amp; tok[i - 1] ! = '*' &amp;&amp; tok[i - 1] != '/') return eval(tok.substr(0, i)) + eval("-" + tok.substr(i + 1, tok.length() -我 - 1)); }` 并将 - 更改为 +,同时将 - 传递给其余的求值,这样操作顺序就不会中断。 (2认同)