在.NET中是否有一个stringmath评估器?

如果我有一个有效的mathexpression式的string,例如:

String s = "1 + 2 * 7"; 

在.NET中是否有内置的库/函数将parsing和评估expression式,并返回结果? 在这种情况下15。

您可以添加对Microsoft脚本控制库(COM)的引用,并使用这样的代码来评估expression式。 (也适用于JScript。)

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

编辑 – C#版本。

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

编辑 – ScriptControl是一个COM对象。 在项目的“添加引用”对话框中,select“COM”选项卡并向下滚动到“Microsoft Script Control 1.0”,然后select“确定”。

奇怪的是,这个着名的老问题没有一个答案,暗示了内置的DataTable.Compute – “诡计”。 这里是。

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

expression式中支持以下算术运算符:

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

更多信息: expression式语法处的DataColumn.Expression

对于在Silverlight上使用C#开发的人来说,这里有一个非常简洁的技巧,我刚刚发现可以通过调用Javascript引擎来评估expression式:

 double result = (double) HtmlPage.Window.Eval("15 + 35"); 

你见过http://ncalc.codeplex.com吗?;

它是可扩展的,快速的(例如有自己的caching)使您能够在运行时通过处理EvaluateFunction / EvaluateParameter事件来提供自定义函数和variables。 它可以parsing的示例expression式:

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

它也处理unicode和许多数据types本地。 如果你想改变语法,它带有一个鹿angular文件。 还有一个支持MEF加载新function的分支。

其实有一种内置的 – 你可以使用XPath命名空间! 虽然它要求您重新格式化string以确认XPath符号。 我用这样的方法来处理简单的expression式:

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

最初我用muparser的c#包装器。 这非常快 我知道的唯一更快的解决scheme是exprtk 。 如果您正在寻找其他解决scheme,您可以检查基准 。

但是,如果使用.Net,则可以使用内置支持在运行时编译代码。 这个想法是有一个“模板”源文件,例如embedded式资源,您可以在其中replace评估公式。 然后,将准备好的类源代码传递给编译器。

一个基本的模板可能是这样的:

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

注意expression式将被放入的%公式%

编译使用类CSharpCodeProvider。 我不想在这里input完整的信息。 但是这个答案可能有帮助:

在载入内存程序集之后,可以创build类的实例并调用EvalCode。

最近我使用的是mXparser,它是.NET和JAVA的mathparsing器库。 mXparser支持基本公式以及非常花哨/复杂的公式(包括variables,函数,运算符,迭代和recursion)。

https://mxparser.codeplex.com/

http://mathparser.org/

几个用法示例:

例1:

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

例2:

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

例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(); 

最好的祝福

如果你需要非常简单的东西,你可以使用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") 

我也会看看Jace( https://github.com/pieterderycke/Jace )。 Jace是一个高性能的mathparsing器和计算引擎,支持所有的.NET风格(.NET 4.x,Windows Phone,Windows Store,…)。 Jace也可以通过NuGet: https : //www.nuget.org/packages/Jace

一个简单的mathparsing器很容易构build,只需要几行代码:

以这个灵活的例子:

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

通过包围堆栈来启用优先级就足够了,比如通过recursion存档。 括号之间的任何东西放在一个新的堆栈上。 最后,您可以通过lambdaexpression式以清晰可读的方式支持math运算。

现在罗斯林还有另一种select:

你可以使用CodeAnalysis.CSharp.Scripting库来做到这一点。

 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包:

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

几年前,我实现了一个expression式parsing器,并且最近在GitHub和Nuget:Albatross.Expression中发布了它的一个版本。 它包含一个ExecutionContext类,可以评估一组expression式,如:

  • MV =价格*数量;
  • 价格=(Bid + Ask)/ 2;
  • Bid = .6;
  • Ask = .8;

它还内置了循环引用检查function,可以避免堆栈溢出。

快速轻量级expression式评估器

https://flee.codeplex.com

语言参考

  • ArithmeticOperators示例:a * 2 + b ^ 2 – 100%5
  • 比较运算符示例:a <> 100
  • AndOrXorNotOperators示例(逻辑):a> 100而不是b = 100
  • ShiftOperators示例:100 >> 2
  • 级联示例:“abc”+“def”
  • 索引示例:arr [i + 1] + 100
  • 字面
  • 施放示例:100 + cast(obj,int)
  • 条件操作符示例:如果(a> 100和b> 10,“都大于”,“小于”)
  • InOperator示例(列表):If(100 in(100,200,300,-1),“in”,“not in”)
  • types上的重载操作符

例如:

 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) 

输出:50

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