¿Hay un evaluador matemático de cuerdas en .NET?

Si tengo una cadena con una expresión matemática válida, como:

String s = "1 + 2 * 7"; 

¿Hay una biblioteca / función incorporada en .NET que analizará y evaluará esa expresión para mí y devolverá el resultado? En este caso 15.

Puede agregar una referencia a Microsoft Script Control Library (COM) y usar un código como este para evaluar una expresión. (También funciona para JScript)

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

Edición – Versión C #.

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

Editar – El ScriptControl es un objeto COM. En el cuadro de diálogo “Agregar referencia” del proyecto, seleccione la pestaña “COM” y desplácese hacia abajo hasta “Microsoft Script Control 1.0” y seleccione Aceptar.

Es extraño que esta famosa y vieja pregunta no tenga una respuesta que sugiera el DataTable.Compute incorporado – “truco”. Aquí está.

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

Los siguientes operadores aritméticos son compatibles con expresiones:

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

Más información: DataColumn.Expression en Expression Syntax .

Para cualquiera que se desarrolle en C # en Silverlight, aquí hay un truco muy bueno que acabo de descubrir que permite la evaluación de una expresión llamando al motor de Javascript:

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

¿Has visto http://ncalc.codeplex.com ?

Es extensible, rápido (por ejemplo, tiene su propio caché) le permite proporcionar funciones personalizadas y varaibles en tiempo de ejecución mediante el manejo de eventos EvaluateFunction / EvaluateParameter. Ejemplos de expresiones que puede analizar:

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

También maneja unicode y muchos tipos de datos de forma nativa. Viene con un archivo de astas si quieres cambiar la gramática. También hay un tenedor que soporta MEF para cargar nuevas funciones.

De hecho, hay una especie de uno integrado: ¡puedes usar el espacio de nombres XPath! Aunque requiere que vuelva a formatear la cadena para confirmar con la notación XPath. He usado un método como este para manejar expresiones simples:

  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("")) .CreateNavigator() .Evaluate(xsltExpression); } 

Inicialmente usé el contenedor c # para muparser . Esto fue muy rápido. La única solución más rápida que conozco es exprtk . Si está buscando otras soluciones, puede consultar el punto de referencia .

Pero en el caso de .Net puede usar el soporte integrado para comstackr el código en tiempo de ejecución. La idea es tener un archivo fuente “plantilla” como, por ejemplo, un recurso incrustado donde puede reemplazar la fórmula para la evaluación. Luego pasas este código fuente-clase preparado al comstackdor.

Una plantilla básica podría verse así:

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

Observe el% formula% donde se colocará la expresión.

Para comstackr use la clase CSharpCodeProvider. No quiero poner la fuente completa aquí. Pero esta respuesta podría ayudar:

Después de cargar el ensamblaje en memoria, puede crear una instancia de su clase y llamar a EvalCode.

Recientemente estaba usando mXparser, que es una biblioteca de análisis matemático para .NET y JAVA. mXparser es compatible con fórmulas básicas y complejas (incluidas variables, funciones, operadores, iteración y recursividad).

https://mxparser.codeplex.com/

http://mathparser.org/

Algunos ejemplos de uso:

Ejemplo 1:

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

Ejemplo 2:

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

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

Atentamente

Otra opción ahora que Roslyn está disponible:

Puede usar la biblioteca CodeAnalysis.CSharp.Scripting para esto.

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

paquetes nuget:

       

Si necesita algo muy simple, puede usar 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") 

También echaré un vistazo a Jace ( https://github.com/pieterderycke/Jace ). Jace es un analizador matemático de alto rendimiento y un motor de cálculo que admite todos los sabores .NET (.NET 4.x, Windows Phone, Windows Store, …). Jace también está disponible a través de NuGet: https://www.nuget.org/packages/Jace

Un analizador matemático simple es bastante fácil de construir y solo requiere unas pocas líneas de código:

Toma este ejemplo flexible:

 class RPN { public static double Parse( Stack strStk ) { if (strStk == null || strStk.Count == 0 ) { return 0; } Stack numStk = new Stack(); double result = 0; Func 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 strStk = new Stack( Regex.Split(str, @"([()*+\/-])", RegexOptions.Multiline).Reverse() ); RPN.Parse(strStk); 

Para habilitar la precedencia colocando entre paréntesis una stack de stacks será suficiente, como archivado por recursión. Cualquier cosa entre paréntesis se pone en una nueva stack. Finalmente, puedes apoyar las operaciones matemáticas de una forma legible por lambdas.

Implementé un analizador de expresiones hace unos años y publiqué una versión de él en GitHub y Nuget: Albatross.Expression recientemente. Contiene una clase ExecutionContext que puede evaluar un conjunto de expresiones tales como:

  • MV = Precio * Cantidad;
  • Precio = (oferta + pedir) / 2;
  • Bid = .6;
  • Preguntar = .8;

También ha incorporado un control de referencia circular que es útil para evitar un desbordamiento de stack.

Huir rápido Evaluador de Expresión Ligera

https://flee.codeplex.com

Referencia idiomática

  • Ejemplo de ArithmeticOperators: a * 2 + b ^ 2 – 100% 5
  • Ejemplo de ComparisonOperators: a <> 100
  • Ejemplo de AndOrXorNotOperators (lógico): a> 100 y no b = 100
  • Ejemplo de ShiftOperators: 100 >> 2
  • Ejemplo de concatenación: “abc” + “def”
  • Ejemplo de indexación: arr [i + 1] + 100
  • Literales
  • Ejemplo de lanzamiento: 100 + lanzamiento (obj, int)
  • Ejemplo ConditionalOperator: If (a> 100 yb> 10, “both greater”, “less”)
  • Ejemplo de InOperator (Lista): If (100 in (100, 200, 300, -1), “in”, “not in”)
  • Operadores sobrecargados en tipos

Ejemplo:

 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) 

La salida: 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("")) .CreateNavigator() .Evaluate(xsltExpression); // ReSharper restre PossibleNullReferenceException } } }