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 : 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.
Aunque esto está marcado como la respuesta, fue hace 10 años y COM está un poco muerto ahora. Prefiero la respuesta de DataTable.Compute a continuación.
dwilliss
64
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:
hubo una respuesta de ma81xx el 15 de noviembre de
2011
1
Tiene razón, pero eso no fue usando el método Compute.
Tim Schmelter
Su ejemplo me da System.InvalidCastException no fue manejado por el código de usuario HResult = -2147467262 ¿Cómo puedo solucionarlo?
Yuliia Ashomok
A mí me funciona, ¿ha utilizado este código de muestra? Utilice el depurador e inspeccione el valor del resultado, se menciona el tipo.
Tim Schmelter
28
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");
Me pregunto si podría hacer referencia a esto en otro lugar. Probablemente no, pero sería genial.
Joel Coehoorn
4
Como esto evalúa el código Javascript arbitrario, probablemente desee asegurarse de desinfectar su entrada y asegurarse de que no está mostrando directamente el resultado. (Creo que esta sería una buena manera de presentar XSS sin darme cuenta)
Dan Esparza
Intente ingresar números con un cero a la izquierda, el resultado no es confiable. "054 + 6" le da 50 por ejemplo.
Terry
9
@djerry, eso se debe a que el evaluador de JS considera los números con un cero a la izquierda, y el octal 054 es igual al decimal 44.
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.
Esto es lo que usé para mi solucionador de ecuaciones diferenciales que tomó la entrada de un usuario. La pregunta está aquí
kleineg
15
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:
publicstaticdoubleEvaluate(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í:
publicclassCSCodeEvaler
{
publicdoubleEvalCode()
{
return last = Convert.ToDouble(%formula%);
}
publicdouble last = 0;
publicconstdouble pi = Math.PI;
publicconstdouble e = Math.E;
publicdoublesin(doublevalue) { return Math.Sin(value); }
publicdoublecos(doublevalue) { return Math.Cos(value); }
publicdoubletan(doublevalue) { 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.
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).
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.
Esta es la mejor biblioteca que encontré. Sin embargo, no admite ningún tipo de datos que no sea el número. Necesito DateTime y String ... ¿conoces alguna buena alternativa?
Homam
@Homam ¿Encontró una alternativa para las operaciones de cuerdas
Ramakrishna Reddy
5
Si necesita algo muy simple, puede usar DataTable:-)
Dim dt AsNew DataTable
dt.Columns.Add("A", GetType(Integer))
dt.Columns.Add("B", GetType(Integer))
dt.Columns.Add("C", GetType(Integer))
dt.Rows.Add(NewObject() {12, 13, DBNull.Value})
Dim boolResult AsBoolean = dt.Select("A>B-2").Length > 0
dt.Columns.Add("result", GetType(Integer), "A+B*2+ISNULL(C,0)")
Dim valResult AsObject = 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:
classRPN
{
publicstaticdoubleParse( Stack<string> strStk )
{
if (strStk == null || strStk.Count == 0 )
{
return0;
}
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.
-1: Simplemente combine esto en la respuesta @cbp. Hay CERO necesidad de tener dos respuestas que son fundamentalmente idénticas cuando podemos tener una respuesta fantástica.
Robert MacLean
1
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:
MV = Precio * Cant;
Precio = (oferta + demanda) / 2;
Oferta = .6;
Preguntar = .8;
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.
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)
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.
fuente
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:
Más información:
DataColumn.Expression
en Expression Syntax .fuente
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");
fuente
¿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.
fuente
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); }
fuente
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.
fuente
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" />
fuente
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/
https://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();
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
fuente
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")
fuente
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
fuente
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.
fuente
100.5 + 300.5 - 100 * 10 / 100 = 30.1
vs391
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 } } }
fuente
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.
fuente
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.
fuente
Evaluador de expresiones ligeras Flee Fast
https://flee.codeplex.com
Referencia idiomática
Ejemplo:
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
fuente
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)); } } }
No olvides cargar
<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />
fuente