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 por mí y devolverá el resultado? En este caso 15.
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 por mí y devolverá el resultado? En este caso 15.
Respuestas:
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)
Editar : 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 : ScriptControl es un objeto COM. En el cuadro de diálogo "Agregar referencia" del proyecto, seleccione la pestaña "COM", 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"truco" incorporado . Aquí está.
double result = Convert.ToDouble(new DataTable().Compute("1 + 2 * 7", null));
Los siguientes operadores aritméticos se admiten en expresiones:
+ (addition)
- (subtraction)
* (multiplication)
/ (division)
% (modulus)
Más información: DataColumn.Expressionen Expression Syntax .
Para cualquiera que desarrolle en C # en Silverlight, aquí hay un truco bastante bueno que acabo de descubrir que permite la evaluación de una expresión llamando al motor Javascript:
double result = (double) HtmlPage.Window.Eval("15 + 35");
¿Has visto http://ncalc.codeplex.com ?
Es extensible, rápido (por ejemplo, tiene su propia caché) le permite proporcionar funciones personalizadas y variables en tiempo de ejecución mediante el manejo de eventos EvaluateFunction / EvaluateParameter. Expresiones de ejemplo 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 asta si desea cambiar la gramática. También hay una bifurcación que admite MEF para cargar nuevas funciones.
En realidad, hay 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("<r/>"))
.CreateNavigator()
.Evaluate(xsltExpression);
}
Inicialmente utilicé la envoltura de 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 incorporado para compilar código en tiempo de ejecución. La idea es tener un archivo fuente de "plantilla" como, por ejemplo, un recurso incrustado donde se puede reemplazar la fórmula para la evaluación. Luego pasa este código fuente de clase preparado al compilador.
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% fórmula% donde se incluirá la expresión.
Para compilar use la clase CSharpCodeProvider. No quiero poner la fuente completa aquí. Pero esta respuesta podría ayudar:
Una vez que haya cargado el ensamblado en memoria, puede crear una instancia de su clase y llamar a EvalCode.
Otra opción más 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:
<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" />
Recientemente estaba usando mXparser, que es una biblioteca de analizador matemático para .NET y JAVA. mXparser admite fórmulas básicas así como fórmulas muy sofisticadas / complicadas (incluidas variables, funciones, operadores, iteración y recursión).
https://mxparser.codeplex.com/
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();
Encontrado recientemente: en caso de que desee probar la sintaxis (y ver el caso de uso avanzado), puede descargar la aplicación Scalar Calculator que funciona con mXparser.
Atentamente
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ía un vistazo a Jace ( https://github.com/pieterderycke/Jace ). Jace es un motor de cálculo y analizador matemático de alto rendimiento que admite todos los tipos de .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:
Tome este ejemplo flexible:
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);
Para habilitar la precedencia, será suficiente poner entre corchetes una pila de pilas, como archivadas por recursividad. Todo lo que esté entre paréntesis se coloca en una nueva pila. Finalmente, puede admitir operaciones matemáticas de una manera legible y limpia mediante lambdas.
100.5 + 300.5 - 100 * 10 / 100 = 30.1vs391
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
}
}
}
Implementé un analizador de expresiones hace unos años y había publicado una versión en GitHub y Nuget: Albatross.Expression recientemente. Contiene una clase ExecutionContext que puede evaluar un conjunto de expresiones como:
También tiene una verificación de referencia circular incorporada que es útil para evitar un desbordamiento de la pila.
Puede usar la biblioteca Math-Expression-Evaluator de la que soy autor. Es compatible con expresiones simples, tales como 2.5+5.9, 17.89-2.47+7.16, 5/2/2+1.5*3+4.58, expresiones con paréntesis (((9-6/2)*2-4)/2-6-1)/(2+24/(2+4))y expresiones con 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});
También puede pasar parámetros como variables con nombre:
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);
Es compatible con .Net Standard 2.0, por lo que se puede utilizar desde .Net Core así como desde proyectos de .Net Full Framework y no tiene dependencias externas.
Evaluador de expresiones ligeras Flee Fast
Referencia idiomática
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
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));
}
}
}
No olvides cargar
<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />