如果我有一个包含有效数学表达式的字符串,例如:
String s = "1 + 2 * 7";
.NET中是否有内置的库/函数来解析和评估该表达式并返回结果?在这种情况下15。
答案 0 :(得分:57)
奇怪的是,这个着名的旧问题没有一个答案暗示内置DataTable.Compute
- “技巧”。在这里。
double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));
表达式支持以下算术运算符:
+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)
更多信息:表达式语法。{/ 3>。DataColumn.Expression
答案 1 :(得分:52)
您可以添加对Microsoft脚本控件库(COM)的引用,并使用这样的代码来计算表达式。 (也适用于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对象。在项目的“添加引用”对话框中,选择“COM”选项卡,然后向下滚动到“Microsoft Script Control 1.0”并选择“确定”。
答案 2 :(得分:28)
对于在Silverlight上使用C#开发的任何人来说,这是一个非常巧妙的技巧,我刚刚发现它允许通过调用Javascript引擎来评估表达式:
double result = (double) HtmlPage.Window.Eval("15 + 35");
答案 3 :(得分:21)
你见过http://ncalc.codeplex.com吗?
它是可扩展的,快速的(例如有自己的缓存)使您能够通过处理EvaluateFunction / EvaluateParameter事件在运行时提供自定义函数和变量。它可以解析的示例表达式:
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&许多数据类型原生。如果你想改变语法,它会附带一个鹿茸文件。还有一个支持MEF加载新功能的fork。
答案 4 :(得分:15)
实际上有一种内置的 - 你可以使用XPath命名空间! 虽然它需要您重新格式化字符串以使用XPath表示法进行确认。我使用这样的方法来处理简单的表达式:
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);
}
答案 5 :(得分:11)
最初我使用了muparser的c#包装器。这非常快。我所知道的唯一更快的解决方案是exprtk。如果您正在寻找其他解决方案,可以查看benchmark。
但是对于.Net,您可以使用内置支持在运行时编译代码。该想法是具有“模板”源文件,例如,嵌入式资源,您可以在其中替换评估公式。然后将这个准备好的类源代码传递给编译器。
基本模板可能如下所示:
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); }
...
注意表达式将放入的%formula%。
要编译,请使用CSharpCodeProvider类。我不想在这里填写完整的来源。但是this answer可能有所帮助:
加载内存程序集后,您可以创建类的实例并调用EvalCode。
答案 6 :(得分:8)
最近我使用的是mXparser,它是.NET和JAVA的数学解析器库。 mXparser支持基本公式以及非常奇特/复杂的公式(包括变量,函数,运算符,迭代和递归)。
https://mxparser.codeplex.com/
一些用法示例:
示例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();
最近发现 - 如果您想尝试语法(并查看高级用例),可以下载由mXparser提供支持的Scalar Calculator app。
祝你好运
答案 7 :(得分:7)
罗斯林可用的另一个选择是:
您可以使用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" />
答案 8 :(得分:5)
如果您需要非常简单的事情,可以使用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")
答案 9 :(得分:3)
我还要看看Jace(https://github.com/pieterderycke/Jace)。 Jace是一个高性能的数学解析器和计算引擎,支持所有.NET风格(.NET 4.x,Windows Phone,Windows Store,...)。 Jace也可以通过NuGet获得:https://www.nuget.org/packages/Jace
答案 10 :(得分:3)
一个简单的数学解析器很容易构建,只需要几行代码:
采取这个灵活的例子:
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);
要通过包围一堆堆栈来启用优先级就足够了,例如通过递归存档。括号之间的任何内容都放在新堆栈上。 最后,您可以通过lambdas以清晰易读的方式支持数学运算。
答案 11 :(得分: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:
It also has built in circular reference check which is useful to avoid a stack overflow.
答案 12 :(得分:1)
您可以使用我创建的Math-Expression-Evaluator库。它支持简单的表达式,例如2.5+5.9
,17.89-2.47+7.16
,5/2/2+1.5*3+4.58
,带有括号(((9-6/2)*2-4)/2-6-1)/(2+24/(2+4))
的表达式以及具有变量的表达式:
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});
您还可以将参数作为命名变量传递:
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);
它支持.Net Standard 2.0,因此可以在.Net Core和.Net Full Framework项目中使用,并且它没有任何外部依赖性。
答案 13 :(得分:0)
回避率 快速轻量级表达评估器
语言参考
示例:
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
答案 14 :(得分:0)
roles/
别忘了加载
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));
}
}
}
答案 15 :(得分: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
}
}
}
答案 16 :(得分:0)
没有内置的解决方案,但有一些简单的方法可以让它发挥作用。
现在这个问题至少有两个很好的新解决方案:使用符号代数 AngouriMath 或通用算法库 Towel。
你可以做到
using AngouriMath;
Entity expr = "1 + 2 + sqrt(2)";
var answer = (double)expr.EvalNumerical();
(默认情况下它以高精度计算,可能也有用)
或者编译它
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));
以便它可以用于时间关键的代码。
你可以这样做
using Towel.Mathematics;
var expression = Symbolics.Parse<double>("(2 + 2 * 2 - (2 ^ 4)) / 2");
Console.WriteLine(expression.Simplify());
它会直接将您的表达式计算为 double
。
两者都可以通过 Nuget 安装:AngouriMath、Towel。