16

Is there an easy way to parse a simple math expression represented as a string such as (x+(2*x)/(1-x)), provide a value for x, and get a result?

I looked at the VSAEngine per several online examples, however, I am getting a warning that this assembly has been deprecated and not to use it.

If it makes any differences, I am using .NET 4.0.

Steve Konves
  • 2,648
  • 3
  • 25
  • 44
Brandon
  • 10,744
  • 18
  • 64
  • 97

9 Answers9

19

I urge caution against choosing an existing generic expression evaluator over a purpose-built math evaluator. The reason for this is expression evaluators are not limited to math. A clever individual could use this to create an instance of any type in the framework and call any method on the type, and that would allow him to do some decidedly unwelcome things. For example: new System.Net.WebClient().DownloadFile("illegalchildpornurl", "C:\openme.gif") will evaluate just fine in most of those, and do just what it sounds like it would (and make you a felon at the same time).

This doesn't mean don't look for something that's already written; it just means be careful. You want one that does math, and only math. Most of what's already out there isn't that picky.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
13

I was recently using mXparser, which is a math parser library. It gives you a lot of flexibility, such as variables, functions, constants, operators. You will find below a few usage examples:

Example 1 - simple formula

Expression e = new Expression("1 + pi");
double v = e.calculate();

Example 2 - formula with variables, functions, etc.

Argument x = new Argument("x = 2");
Constant a = new Constant("a = sin(10)");
Function f = new Function("f(t) = t^2");
Expression e = new Expression("2*x + a - f(10)", x, a, f);
double v = e.calculate();

https://mxparser.codeplex.com/

https://mathparser.org/

Found recntly - you can try the syntax (and see the use case) via the Scalar Calculator app that is powered by mXparser.

Best regards

Leroy Kegan
  • 1,156
  • 10
  • 9
8

You can try using DataTable.Compute.

A related one is DataColumn.Expression.

Also check out: Doing math in vb.net like Eval in javascript

Note: I haven't used these myself.

Community
  • 1
  • 1
  • Since I was not doing any trig calculations (just simple math), the DataTable.Compute option was the easiest to implement. – Brandon Oct 20 '10 at 16:44
3

I would also have a look at Jace (https://github.com/pieterderycke/Jace). Jace is a high performance math parser and calculation engine that supports all the .NET flavors (.NET 4.x, Windows Phone, Windows Store, ...). Jace is also available through NuGet: https://www.nuget.org/packages/Jace

MuSTaNG
  • 3,832
  • 2
  • 14
  • 6
3

Here is one way to do it. This code is written in Java. Note it does not handle negative numbers right now, but you can add that.

public class ExpressionParser {
public double eval(String exp, Map<String, Double> vars){
    int bracketCounter = 0;
    int operatorIndex = -1;

    for(int i=0; i<exp.length(); i++){
        char c = exp.charAt(i);
        if(c == '(') bracketCounter++;
        else if(c == ')') bracketCounter--;
        else if((c == '+' || c == '-') && bracketCounter == 0){
            operatorIndex = i;
            break;
        }
        else if((c == '*' || c == '/') && bracketCounter == 0 && operatorIndex < 0){
            operatorIndex = i;
        }
    }
    if(operatorIndex < 0){
        exp = exp.trim();
        if(exp.charAt(0) == '(' && exp.charAt(exp.length()-1) == ')')
            return eval(exp.substring(1, exp.length()-1), vars);
        else if(vars.containsKey(exp))
            return vars.get(exp);
        else
            return Double.parseDouble(exp);
    }
    else{
        switch(exp.charAt(operatorIndex)){
            case '+':
                return eval(exp.substring(0, operatorIndex), vars) + eval(exp.substring(operatorIndex+1), vars);
            case '-':
                return eval(exp.substring(0, operatorIndex), vars) - eval(exp.substring(operatorIndex+1), vars);
            case '*':
                return eval(exp.substring(0, operatorIndex), vars) * eval(exp.substring(operatorIndex+1), vars);
            case '/':
                return eval(exp.substring(0, operatorIndex), vars) / eval(exp.substring(operatorIndex+1), vars);
        }
    }
    return 0;
}

}

You need to import java.util.Map.

Here is how I use this code:

    ExpressionParser p = new ExpressionParser();
    Map vars = new HashMap<String, Double>();
    vars.put("x", 2.50);
    System.out.println(p.eval(" 5 + 6 * x - 1", vars));
user4617883
  • 1,277
  • 1
  • 11
  • 21
1

As I answered in this thread (Best Free C# Math Parser using variables, user defined functions, custom operators), you can use Mathos Parser, which you can simply paste into your source code.

        Mathos.Parser.MathParser parser = new Mathos.Parser.MathParser();

        string expr = "(x+(2*x)/(1-x))"; // the expression

        decimal result = 0; // the storage of the result

        parser.LocalVariables.Add("x", 41); // 41 is the value of x

        result = parser.Parse(expr); // parsing

        Console.WriteLine(result); // 38.95
Community
  • 1
  • 1
Artem
  • 1,000
  • 1
  • 15
  • 30
  • Unfortunately this project is hosted at Codeplex, which is closing. I can't manage to even get a look at the source at Codeplex right now. It would be nice if the project could be rehosted on Github or Bitbucket or the like. – Nic Foster Jun 12 '17 at 05:07
  • @NicFoster, please take a look at https://github.com/MathosProject/Mathos-Parser. There are also other versions of it at https://github.com/MathosProject. – Artem Jun 12 '17 at 07:39
1

Another option you may want to look into is the Spring.NET Framework's expression evaluation functionality. It can do a lot more than math, too.

However, the entire Spring.NET Framework might be a bit of overkill for your needs if you don't require the rest of the functionality.

Joshua Rodgers
  • 5,317
  • 2
  • 31
  • 29
1

Related: Equation expression parser with precedence.

Community
  • 1
  • 1
Jared Updike
  • 7,165
  • 8
  • 46
  • 72
0

I recomend you to use MEEL for this.

// parse string to IExpression (symbolic type)
IExpression expression = BaseExpression.Parse("(x+(2*x)/(1-x))");

// create your own collection for attributes
var attributes = new MathAttributeCollection();
// create local variable named "x" with value 5
var attributeX = new ScalarAttrInt("x") {Value = new ScalarConstInt(5)};
attributes.Add(attributeX);

// execute math expression where x=5
var result = expression.Execute(attributes);

MessageBox.Show(result.GetText());
// result: 2.5
supertoha
  • 192
  • 1
  • 8