cref - remarks c#
¿Hay un evaluador matemático de cuerdas en.NET? (14)
¿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.
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.
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("<r/>"))
.CreateNavigator()
.Evaluate(xsltExpression);
}
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 .
Huir rápido Evaluador de Expresión Ligera
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
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 pila.
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 benchmark .
Pero en el caso de .Net puede usar el soporte integrado para compilar 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 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% formula% donde se colocará la expresión.
Para compilar 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.
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:
<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" />
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");
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.
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/
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
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<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 colocando entre paréntesis una pila de pilas será suficiente, como archivado por recursión. Cualquier cosa entre paréntesis se pone en una nueva pila. Finalmente, puedes apoyar las operaciones matemáticas de una forma legible por lambdas.
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
}
}
}