Is there a string math evaluator in .NET?

C#.Net

C# Problem Overview


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.

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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.

Solution 3 - C#

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");

Solution 4 - C#

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.

Solution 5 - C#

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

Solution 6 - C#

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" />

Solution 7 - C#

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.

Solution 8 - C#

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

Solution 9 - C#

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")

Solution 10 - C#

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.

Solution 11 - C#

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

Solution 12 - C#

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.

Solution 13 - C#

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.

Solution 14 - C#

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
        }

    }
}

Solution 15 - C#

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.

Solution 16 - C#

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" />

Solution 17 - C#

Solution 18 - C#

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGuyView Question on Stackoverflow
Solution 1 - C#Tim SchmelterView Answer on Stackoverflow
Solution 2 - C#user21826View Answer on Stackoverflow
Solution 3 - C#GuyView Answer on Stackoverflow
Solution 4 - C#GreyCloudView Answer on Stackoverflow
Solution 5 - C#cbpView Answer on Stackoverflow
Solution 6 - C#CrowcoderView Answer on Stackoverflow
Solution 7 - C#schoetbiView Answer on Stackoverflow
Solution 8 - C#Leroy KeganView Answer on Stackoverflow
Solution 9 - C#ma81xxView Answer on Stackoverflow
Solution 10 - C#GiorgiView Answer on Stackoverflow
Solution 11 - C#MuSTaNGView Answer on Stackoverflow
Solution 12 - C#Lorenz Lo SauerView Answer on Stackoverflow
Solution 13 - C#WhiteBlackGooseView Answer on Stackoverflow
Solution 14 - C#user2069333View Answer on Stackoverflow
Solution 15 - C#Rushui GuanView Answer on Stackoverflow
Solution 16 - C#vtfs271232View Answer on Stackoverflow
Solution 17 - C#BinhView Answer on Stackoverflow
Solution 18 - C#ISCIView Answer on Stackoverflow