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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9329406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:40:55  来源:igfitidea点击:

Evaluating arithmetic expressions from string in C++

c++

提问by Mahdi Ghiasi

I'm searching for a simple way to evaluate a simple math expression from an string, like this:

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

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

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

I just want +and *operations plus (and )signs. And *has more priority than +.

我只想要+*操作加号()标志。并且*比 具有更多的优先级+

采纳答案by Henrik

I think you're looking for a simple recursive descent parser.

我认为您正在寻找一个简单的递归下降解析器

Here's a very simple example:

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

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;
}

回答by Monir

One can try : http://partow.net/programming/exprtk/index.html

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

  1. very simple
  2. only need to include "exprtk.hpp" to your source code.
  3. you can change the value of variables of the expression dynamically.
  4. good starting point: http://partow.net/programming/exprtk/code/exprtk_simple_example_01.cpp
  1. 很简单
  2. 只需要在您的源代码中包含“exprtk.hpp”。
  3. 您可以动态更改表达式的变量值。
  4. 好的起点:http: //partow.net/programming/exprtk/code/exprtk_simple_example_01.cpp

回答by IsaacH

Just to add another alternative, consider trying TinyExprfor this problem. It's open source and self-contained in one source code file. It is actually written in C, but it will compile cleanly as C++ in my experience.

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

Solving your example expression from above is as simple as:

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

#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;
}

回答by Yury

While searching a library for a similar task I found libmatheval. Seems to be a proper thing. Unfortunately, GPL, which is unacceptable for me.

在为类似任务搜索库时,我找到了libmatheval。似乎是理所应当的事情。不幸的是,GPL,这对我来说是不可接受的。

回答by Mustafa Y?ld?z

So I was searching an answer for this question. And I was trying to create my own programming language. For math expressions I was in need of that function.

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

Oke give I'll give it to you. Use it the way you want.

好的,给我给你。以您想要的方式使用它。

/* Code here before is useless now */

This is kind a long and probably an unefficient way of doing such a task. But it gets job done so go for it. Soon I'm planning on adding variable support. But you can do it too, it's pretty easy (I suppose :P).

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

EDIT: I just tidied up the function now it works like magic XD..

编辑:我刚刚整理了这个功能,现在它像魔术一样工作 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...
}

回答by Zoran Horvat

I've written a very simple expression evaluator in C# (minimal changes required to make it C++-compliant). It is based on expression tree building method, only that tree is not actually built but all nodes are evaluated in-place.

我已经用 C# 编写了一个非常简单的表达式计算器(使其符合 C++ 所需的最小更改)。它基于表达式树构建方法,只是实际上并未构建该树,而是就地评估所有节点。

You can find it on this address: Simple Arithmetic Expression Evaluator

你可以在这个地址上找到它:Simple Arithmetic Expression Evaluator