108

If I have a string with a valid math expression such as:

String s = "1 + 2 * 7";

Is there a built in library/function in .NET that will parse and evaluate that expression for me and return the result? In this case 15.

Guy
  • 65,082
  • 97
  • 254
  • 325
  • It may be worth checking out my answer here, which uses Mono.CSharp.Evaluator and should be capable of doing what you require and then some. http://stackoverflow.com/questions/4979423/expression-evaluator-for-c-python-ruby/10532125#10532125 – fostandy May 10 '12 at 10:30
  • See also, [Is it possible to translate a user-entered mathematical equation into C# code at runtime?](http://stackoverflow.com/questions/234217/is-it-possible-to-translate-a-user-entered-mathematical-equation-into-c-code-at) – Rob Kennedy Dec 10 '08 at 04:44
  • I just created a code-only solution to evaluating mathematical expressions in C#. You can see the code at http://www.blackbeltcoder.com/Articles/algorithms/a-c-expression-evaluator. – Jonathan Wood Dec 26 '10 at 19:33
  • 2
    Not a built in one. But there is a pretty comprehensive one [here](http://weblogs.asp.net/pwelter34/archive/2007/05/05/calculator-net-calculator-that-evaluates-math-expressions.aspx). – Strelok Dec 10 '08 at 04:17
  • This library seems to have some bugs. – Philippe Lavoie Mar 04 '11 at 18:34
  • 1
    You can use [The expression evaluator](http://www.codeproject.com/KB/recipes/eval3.aspx) (Eval function in 100% managed .NET) – jadsc Jan 17 '10 at 16:51
  • possible duplicate of [c# evaluating string "3\*(4+2)" yield int 18](http://stackoverflow.com/questions/333737/c-sharp-evaluating-string-342-yield-int-18) – nawfal May 31 '13 at 16:16

18 Answers18

91

Strange that this famous and old question has not an answer that suggests the builtin DataTable.Compute-"trick". Here it is.

double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));

The following arithmetic operators are supported in expressions:

+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)

More informations: DataColumn.Expression at Expression Syntax.

ZivS
  • 2,094
  • 2
  • 27
  • 48
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
57

You could add a reference to Microsoft Script Control Library (COM) and use code like this to evaluate an expression. (Also works for JScript.)

Dim sc As New MSScriptControl.ScriptControl()
sc.Language = "VBScript"
Dim expression As String = "1 + 2 * 7"
Dim result As Double = sc.Eval(expression)

Edit - C# version.

MSScriptControl.ScriptControl sc = new MSScriptControl.ScriptControl();
sc.Language = "VBScript";
string expression = "1 + 2 * 7";
object result = sc.Eval(expression);            
MessageBox.Show(result.ToString());

Edit - The ScriptControl is a COM object. In the "Add reference" dialog of the project select the "COM" tab and scroll down to "Microsoft Script Control 1.0" and select ok.

user21826
  • 3,524
  • 5
  • 28
  • 28
30

Have you seen http://ncalc.codeplex.com ?

It's extensible, fast (e.g. has its own cache) enables you to provide custom functions and varaibles at run time by handling EvaluateFunction/EvaluateParameter events. Example expressions it can parse:

Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)"); 

  e.Parameters["Pi2"] = new Expression("Pi * Pi"); 
  e.Parameters["X"] = 10; 

  e.EvaluateParameter += delegate(string name, ParameterArgs args) 
    { 
      if (name == "Pi") 
      args.Result = 3.14; 
    }; 

  Debug.Assert(117.07 == e.Evaluate()); 

It also handles unicode & many data type natively. It comes with an antler file if you want to change the grammer. There is also a fork which supports MEF to load new functions.

GreyCloud
  • 3,030
  • 5
  • 32
  • 47
  • 1
    Great library. Also available on NUGET – Paul Grimshaw Apr 29 '15 at 16:23
  • This is what I used for my differential equation solver which took a user's input. The question is [here](http://stackoverflow.com/questions/32333134/turn-user-input-string-into-mathematical-function/32378818#32378818) – kleineg Sep 03 '15 at 19:56
  • The latest is at https://github.com/ncalc/ncalc , NCalcSync on NuGet: https://www.nuget.org/packages/NCalcSync – Matt Gregory Jun 16 '23 at 15:11
28

For anybody developing in C# on Silverlight here's a pretty neat trick that I've just discovered that allows evaluation of an expression by calling out to the Javascript engine:

double result = (double) HtmlPage.Window.Eval("15 + 35");
Guy
  • 65,082
  • 97
  • 254
  • 325
  • 4
    As this evaluates arbitrary Javascript code, you probably want to be sure to sanitize your input and make sure you're not directly displaying the result. (I would think this would be a good way to introduce XSS without realizing it) – Dan Esparza Nov 14 '11 at 17:31
  • Try entering numbers with a leading zero, the result isn't reliable. "054 + 6" gives you 50 for example. – Terry Jul 17 '12 at 13:32
  • 10
    @djerry, that is because numbers with a leading zero are considered octal by JS's evaluator, and octal 054 equals decimal 44. – André Leria Dec 13 '12 at 14:11
17

Yet another option now that Roslyn is available:

You can use CodeAnalysis.CSharp.Scripting library for this.

using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;

namespace ExpressionParser
{
    class Program
    {
        static void Main(string[] args)
        {
            //Demonstrate evaluating C# code
            var result = CSharpScript.EvaluateAsync("System.DateTime.Now.AddDays(-1) > System.DateTime.Now").Result;
            Console.WriteLine(result.ToString());

            //Demonstrate evaluating simple expressions
            var result2 = CSharpScript.EvaluateAsync(" 5 * 7").Result;
            Console.WriteLine(result2);
            Console.ReadKey();
        }
    }
}

nuget packages:

<package id="Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Common" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.CSharp" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.CSharp.Scripting" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Scripting" version="1.1.1" targetFramework="net461" />
<package id="Microsoft.CodeAnalysis.Scripting.Common" version="1.1.1" targetFramework="net461" />
th1rdey3
  • 4,176
  • 7
  • 30
  • 66
Crowcoder
  • 11,250
  • 3
  • 36
  • 45
15

Actually there is kind of a built in one - you can use the XPath namespace! Although it requires that you reformat the string to confirm with XPath notation. I've used a method like this to handle simple expressions:

    public static double Evaluate(string expression)
    {
        var xsltExpression = 
            string.Format("number({0})", 
                new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                        .Replace("/", " div ")
                                        .Replace("%", " mod "));

        return (double)new XPathDocument
            (new StringReader("<r/>"))
                .CreateNavigator()
                .Evaluate(xsltExpression);
    }
cbp
  • 25,252
  • 29
  • 125
  • 205
14

Initially I used the c# wrapper for muparser. This was very fast. The only faster solution I know is exprtk. If you are looking for other solutions you can checkout the benchmark.

But in case of .Net you can use the builtin support to compile code at runtime. The idea is to have a "template" source file as e.g. embedded resource where you can replace the formula for the evaluation. Then you pass this prepared class-source-code to the compiler.

A basic template could look like this:

public class CSCodeEvaler
{
    public double EvalCode()
    {
        return last = Convert.ToDouble(%formula%);
    }

    public double last = 0;
    public const double pi = Math.PI;
    public const double e = Math.E;
    public double sin(double value) { return Math.Sin(value); }
    public double cos(double value) { return Math.Cos(value); }
    public double tan(double value) { return Math.Tan(value); }
    ...

Notice the %formula% where the expression will be put in.

To compile use the class CSharpCodeProvider. I do not want to put in the complete source here. But this answer might help:

After you have the in memory assembly loaded you can create an instance of your class and call EvalCode.

Community
  • 1
  • 1
schoetbi
  • 12,009
  • 10
  • 54
  • 72
11

Recently I was using mXparser, which is a math parser library for .NET and JAVA. mXparser supports basic formulas as well as very fancy / complicated ones (including variables, functions, operators, iteration and recursion).

https://mxparser.codeplex.com/

https://mathparser.org/

A few usage examples:

Example 1:

Expression e = new Expression("1+2*7 + (sin(10) - 2)/3");
double v = e.calculate();

Example 2:

Argument x = new Argument("x = 5");
Expression e = new Expression("2*x+3", x);
double v = e.calculate();

Example 3:

Function f = new Function("f(x,y) = sin(x) / cos(y)");
Expression e = new Expression("f(pi, 2*pi) - 2", f);
double v = e.calculate();

Found recently - in case you would like to try the syntax (and see the advanced use case) you can download the Scalar Calculator app that is powered by mXparser.

Best regards

Leroy Kegan
  • 1,156
  • 10
  • 9
6

If you need very simple thing you can use the DataTable :-)

Dim dt As New DataTable
dt.Columns.Add("A", GetType(Integer))
dt.Columns.Add("B", GetType(Integer))
dt.Columns.Add("C", GetType(Integer))
dt.Rows.Add(New Object() {12, 13, DBNull.Value})

Dim boolResult As Boolean = dt.Select("A>B-2").Length > 0

dt.Columns.Add("result", GetType(Integer), "A+B*2+ISNULL(C,0)")
Dim valResult As Object = dt.Rows(0)("result")
Ry-
  • 218,210
  • 55
  • 464
  • 476
ma81xx
  • 101
  • 1
  • 2
4

You can use Math-Expression-Evaluator library that I am author of. It supports simple expressions such as 2.5+5.9, 17.89-2.47+7.16, 5/2/2+1.5*3+4.58, expressions with parentheses (((9-6/2)*2-4)/2-6-1)/(2+24/(2+4)) and expressions with variables:

var a = 6;
var b = 4.32m;
var c = 24.15m;
var engine = new ExpressionEvaluator();
engine.Evaluate("(((9-a/2)*2-b)/2-a-1)/(2+c/(2+4))", new { a, b, c});

You can also pass parameters as named variables:

dynamic dynamicEngine = new ExpressionEvaluator();

var a = 6;
var b = 4.5m;
var c = 2.6m;

dynamicEngine.Evaluate("(c+b)*a", a: 6, b: 4.5, c: 2.6);

It supports .Net Standard 2.0 so can be used from .Net Core as well as .Net Full Framework projects and it doesn't have any external dependencies.

Giorgi
  • 30,270
  • 13
  • 89
  • 125
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

A simple math parser is quite easy to build, and requires only a few lines of code:

Take this flexible example:

class RPN
{
    public static double Parse( Stack<string> strStk )
    {
        if (strStk == null || strStk.Count == 0 )
        {
            return 0;
        }
        Stack<double> numStk = new Stack<double>();
        double result = 0;

        Func<double, double> op = null;
        while (strStk.Count > 0)
        {
            var s = strStk.Pop();
            switch (s)
            {
                case "+":
                    op = ( b ) => { return numStk.Pop() + b; };
                    break;
                case "-":
                    op = ( b ) => { return numStk.Pop() - b; };
                    break;
                case "*":
                    op = ( b ) => { return numStk.Pop() * b; };
                    break;
                case "/":
                    op = ( b ) => { return numStk.Pop() / b; };
                    break;

                default:
                    double.TryParse(s, NumberStyles.Any, out result);
                    if (numStk.Count > 0)
                    {
                        result = op(result);
                    }
                    numStk.Push(result);
                    break;
            }
        }
        return result;
    }
}

....
var str = " 100.5 + 300.5 - 100 * 10 / 100";    
str = Regex.Replace(str, @"\s", "", RegexOptions.Multiline);
Stack<string> strStk = new Stack<string>(
     Regex.Split(str, @"([()*+\/-])", RegexOptions.Multiline).Reverse()
);
RPN.Parse(strStk);

To enable precedence by bracketing a stack of stacks will suffice, such as archived by recursion. Anything between brackets is put on a new stack. Finally you can support math operations in a clean readable fashion by lambdas.

Lorenz Lo Sauer
  • 23,698
  • 16
  • 85
  • 87
  • You might want to verify your answer. `100.5 + 300.5 - 100 * 10 / 100 = 30.1` vs `391` – Tawani Sep 11 '17 at 12:07
  • Your sample will always fail in the default branch of your switch statement result = op(result); <- op is null – Johan Mar 17 '23 at 06:09
2

There's no built-in solution, but there are easy ways to make it work.

There are at least two good new solutions for the problem now: using symbolic algebra AngouriMath or general purpose algorithm library Towel.

AngouriMath

You can do

using AngouriMath;
Entity expr = "1 + 2 + sqrt(2)";
var answer = (double)expr.EvalNumerical();

(by default it computes in high-precision, might be useful too)

Or compile it

Entity expr = "1 + 2 + sqrt(2) + x + y";
Func<double, double, double> someFunc = expr.Compile<double, double, double>("x", "y");
Console.WriteLine(someFunc(3, 5));

so that it could be used in time-critical code.

Towel

Here you can do

using Towel.Mathematics;
var expression = Symbolics.Parse<double>("(2 + 2 * 2 - (2 ^ 4)) / 2");
Console.WriteLine(expression.Simplify());

which would directly compute your expression into double.

Installation

Both can be installed via Nuget: AngouriMath, Towel.

WhiteBlackGoose
  • 110
  • 2
  • 8
1

I implemented an expression parser a few years ago and had published a version of it in GitHub and Nuget:Albatross.Expression recently. It contains a ExecutionContext class that can evaluate a set of expressions such as:

  • MV = Price * Qty;
  • Price = (Bid + Ask)/2;
  • Bid = .6;
  • Ask = .8;

It also has built in circular reference check which is useful to avoid a stack overflow.

Rushui Guan
  • 3,023
  • 1
  • 24
  • 26
1

MathNet.Symbolics

using System;
using static MathNet.Symbolics.SymbolicExpression;
using static System.Console;
using static System.Numerics.Complex;
using Complex = System.Numerics.Complex;

namespace MathEvaluator
{
    class Program
    {
        static readonly Complex i = ImaginaryOne;

        static void Main(string[] args)
        {
            var z = Variable("z");
            Func<Complex, Complex> f = Parse("z * z").CompileComplex(nameof(z));
            Complex c = 1 / 2 - i / 3;
            WriteLine(f(c));


            var x = Variable("x");
            Func<double, double> g = Parse("x * x + 5 * x + 6").Compile(nameof(x));
            double a = 1 / 3.0;
            WriteLine(g(a));
        }
    }
}

Don't forget to load

<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165
1

Try my matheval library on github

repo: https://github.com/matheval/expression-evaluator-c-sharp

nuget: https://www.nuget.org/packages/org.matheval/

Binh
  • 261
  • 2
  • 4
0
namespace CalcExp
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            double res = Evaluate("4+5/2-1");

            Console.WriteLine(res);

        }

        public static double Evaluate(string expression)
        {
            var xsltExpression =
                string.Format("number({0})",
                    new Regex(@"([\+\-\*])").Replace(expression, " ${1} ")
                                            .Replace("/", " div ")
                                            .Replace("%", " mod "));

// ReSharper disable PossibleNullReferenceException
            return (double)new XPathDocument
                (new StringReader("<r/>"))
                    .CreateNavigator()
                    .Evaluate(xsltExpression);
// ReSharper restore PossibleNullReferenceException
        }

    }
}
BlackBear
  • 22,411
  • 10
  • 48
  • 86
  • 3
    -1: Just merge this into @cbp answer. There is ZERO need to have two answers which are fundamentally identical when we can have one fantastic answer. – Robert MacLean Oct 15 '14 at 13:17
0

Flee Fast Lightweight Expression Evaluator

https://flee.codeplex.com

Language Reference

  • ArithmeticOperators Example: a*2 + b ^ 2 - 100 % 5
  • ComparisonOperators Example: a <> 100
  • AndOrXorNotOperators Example (logical): a > 100 And Not b = 100
  • ShiftOperators Example: 100 >> 2
  • Concatenation Example: "abc" + "def"
  • Indexing Example: arr[i + 1] + 100
  • Literals
  • Casting Example: 100 + cast(obj, int)
  • ConditionalOperator Example: If(a > 100 and b > 10, "both greater", "less")
  • InOperator Example (List): If(100 in (100, 200, 300, -1), "in", "not in")
  • Overloaded Operators On Types

Example :

Imports Ciloci.Flee
Imports Ciloci.Flee.CalcEngine
Imports System.Math

    Dim ec As New Ciloci.Flee.ExpressionContext
    Dim ex As IDynamicExpression
    ec.Imports.AddType(GetType(Math))

    ec.Variables("a") = 10            
    ec.Variables("b") = 40               
    ex = ec.CompileDynamic("a+b")

    Dim evalData    
    evalData = ex.Evaluate()
    Console.WriteLine(evalData)

The output : 50

ISCI
  • 346
  • 3
  • 7