Is er een string-wiskunde-evaluator in .NET?

Als ik een string heb met een geldige wiskundige uitdrukking zoals:

String s = "1 + 2 * 7";

Is er een ingebouwde bibliotheek/functie in .NET die die uitdrukking voor mij zal ontleden en evalueren en het resultaat zal retourneren? In dit geval 15.


Antwoord 1, autoriteit 100%

Vreemd dat deze beroemde en oude vraag geen antwoord heeft dat suggereert dat de ingebouwde DataTable.Compute-“truc”. Hier is het.

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

De volgende rekenkundige operatoren worden ondersteund in uitdrukkingen:

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

Meer informatie: DataColumn.Expressionop Expressiesyntaxis.


Antwoord 2, autoriteit 74%

Je zou een verwijzing naar Microsoft Script Control Library (COM) kunnen toevoegen en dergelijke code kunnen gebruiken om een ​​uitdrukking te evalueren. (Werkt ook voor JScript.)

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

Bewerken– C#-versie.

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

Bewerken– De ScriptControl is een COM-object. Selecteer in het dialoogvenster “Referentie toevoegen” van het project het tabblad “COM” en scrol omlaag naar “Microsoft Script Control 1.0” en selecteer ok.


Antwoord 3, autoriteit 38%

Voor iedereen die zich in C# op Silverlight ontwikkelt, is hier een aardige truc die ik zojuist heb ontdekt en waarmee een expressie kan worden geëvalueerd door de Javascript-engine aan te roepen:

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

Antwoord 4, autoriteit 36%

Heb je http://ncalc.codeplex.comgezien?

Het is uitbreidbaar, snel (heeft bijvoorbeeld een eigen cache) stelt u in staat om tijdens runtime aangepaste functies en variabelen te bieden door EvaluateFunction/EvaluateParameter-gebeurtenissen af ​​te handelen. Voorbeelduitdrukkingen die het kan ontleden:

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

Het behandelt ook unicode & veel gegevenstype native. Het wordt geleverd met een geweibestand als u de grammatica wilt wijzigen. Er is ook een vork die MEF ondersteunt om nieuwe functies te laden.


Antwoord 5, autoriteit 20%

Eigenlijk is er een soort ingebouwde – u kunt de XPath-naamruimte gebruiken!
Hoewel het vereist dat u de tekenreeks opnieuw formatteert om te bevestigen met XPath-notatie. Ik heb een methode als deze gebruikt om eenvoudige uitdrukkingen te verwerken:

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

Antwoord 6, autoriteit 20%

Nog een andere optie nu Roslyn beschikbaar is:

U kunt hiervoor de CodeAnalysis.CSharp.Scripting-bibliotheek gebruiken.

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

nugetpakketten:

<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" />

Antwoord 7, autoriteit 19%

Aanvankelijk gebruikte ik de c#-wrapper voor muparser. Dit was erg snel. De enige snellere oplossing die ik ken is exprtk. Als u op zoek bent naar andere oplossingen, kunt u de benchmarkbekijken.

Maar in het geval van .Net kun je de ingebouwde ondersteuning gebruiken om code te compileren tijdens runtime. Het idee is om een ​​”sjabloon” bronbestand te hebben zoals b.v. embedded resource waar u de formule voor de evaluatie kunt vervangen. Vervolgens geef je deze voorbereide class-source-code door aan de compiler.

Een basissjabloon kan er als volgt uitzien:

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

Let op de %formule% waar de uitdrukking zal worden ingevoerd.

Gebruik de klasse CSharpCodeProvider om te compileren. Ik wil hier niet de volledige bron vermelden. Maar dit antwoordkan helpen:

Nadat je de assembly in het geheugen hebt geladen, kun je een instantie van je klasse maken en EvalCode aanroepen.


Antwoord 8, autoriteit 12%

Onlangs gebruikte ik mXparser, een wiskundige parserbibliotheek voor .NET en JAVA. mXparser ondersteunt zowel basisformules als zeer mooie / gecompliceerde formules (inclusief variabelen, functies, operators, iteratie en recursie).

https://mxparser.codeplex.com/

https://mathparser.org/

Een paar gebruiksvoorbeelden:

Voorbeeld 1:

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

Voorbeeld 2:

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

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

Recent gevonden – als je de syntaxis wilt proberen (en de geavanceerde use-case wilt zien), kun je de ScalarRekenmachineappdie wordt aangedreven door mXparser.

Met vriendelijke groeten


Antwoord 9, autoriteit 8%

Als je iets heel eenvoudigs nodig hebt, kun je de DataTablegebruiken 🙂

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")

Antwoord 10, autoriteit 5%

Je kunt de bibliotheek Math-Expression-Evaluatorgebruiken waarvan ik de auteur ben. Het ondersteunt eenvoudige uitdrukkingen zoals 2.5+5.9, 17.89-2.47+7.16, 5/2/2+1.5*3+4.58, uitdrukkingen met haakjes (((9-6/2)*2-4)/2-6-1)/(2+24/(2+4))en uitdrukkingen met variabelen:

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

U kunt parameters ook doorgeven als benoemde variabelen:

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

Het ondersteunt .Net Standard 2.0 en kan dus zowel vanuit .Net Core als .Net Full Framework-projecten worden gebruikt en heeft geen externe afhankelijkheden.


Antwoord 11, autoriteit 4%

Ik zou ook eens kijken naar Jace (https://github.com/pieterderycke/Jace). Jace is een krachtige wiskundige parser en berekeningsengine die alle .NET-smaken ondersteunt (.NET 4.x, Windows Phone, Windows Store, …). Jace is ook beschikbaar via NuGet: https://www.nuget.org/packages/Jace


Antwoord 12, autoriteit 4%

Een eenvoudige wiskundige parser is vrij eenvoudig te bouwen en vereist slechts een paar regels code:

Neem dit flexibele voorbeeld:

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

Als u voorrang wilt inschakelen door tussen haakjes te plaatsen, is een stapel stapels voldoende, zoals gearchiveerd door recursie. Alles tussen haakjes wordt op een nieuwe stapel geplaatst.
Eindelijk kun je wiskundige bewerkingen op een duidelijk leesbare manier ondersteunen door lambdas.


Antwoord 13

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
        }
    }
}

Antwoord 14

Ik heb een paar jaar geleden een expressie-parser geïmplementeerd en een versie ervan gepubliceerd in GitHuben Nuget:Albatross.Expressiononlangs. Het bevat een ExecutionContext-klasse die een reeks expressies kan evalueren, zoals:

  • MV = Prijs * Aantal;
  • Prijs = (bod + vraag)/2;
  • Bod = .6;
  • Vraag = .8;

Het heeft ook een ingebouwde kringverwijzingscontrole, wat handig is om een ​​overloop van de stapel te voorkomen.


Antwoord 15

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

Vergeet niet te laden

<PackageReference Include="MathNet.Symbolics" Version="0.20.0" />

Antwoord 16

Er is geen ingebouwde oplossing, maar er zijn eenvoudige manieren om het te laten werken.

Er zijn nu minstens twee goede nieuwe oplossingen voor het probleem: het gebruik van symbolische algebra AngouriMathof algemene algoritmebibliotheek Handdoek.

AngouriMath

Je kunt doen

using AngouriMath;
Entity expr = "1 + 2 + sqrt(2)";
var answer = (double)expr.EvalNumerical();

(standaard berekent het met hoge precisie, kan ook handig zijn)

Of compileer het

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

zodat het kan worden gebruikt in tijdkritische code.

Handdoek

Hier kun je doen

using Towel.Mathematics;
var expression = Symbolics.Parse<double>("(2 + 2 * 2 - (2 ^ 4)) / 2");
Console.WriteLine(expression.Simplify());

die uw uitdrukking rechtstreeks zou berekenen in double.

Installatie

Beide kunnen worden geïnstalleerd via Nuget: AngouriMath, Handdoek.


Antwoord 17

Probeer mijn wiskundige bibliotheek op github

repo: https://github.com/matheval/expression-evaluator-c -scherp

nuget: https://www.nuget.org/packages/org.matheval/


Antwoord 18

Vluchten
Snelle lichtgewicht expressie-evaluator

https://flee.codeplex.com

Taalreferentie

  • ArithmeticOperators Voorbeeld: a*2 + b ^ 2 – 100 % 5
  • ComparisonOperators Voorbeeld: a <> 100
  • AndOrXorNotOperators Voorbeeld (logisch): a > 100 en niet b = 100
  • ShiftOperators Voorbeeld: 100 >> 2
  • Aaneenschakeling Voorbeeld: “abc” + “def”
  • Indexeringsvoorbeeld: arr[i + 1] + 100
  • Letterlijk
  • Castingvoorbeeld: 100 + cast(obj, int)
  • VoorwaardelijkOperator-voorbeeld: If(a > 100 en b > 10, “beide groter”, “minder”)
  • InOperator-voorbeeld (lijst): If(100 in (100, 200, 300, -1), “in”, “not in”)
  • Overbelaste operators op typen

Voorbeeld:

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)

De output: 50

Other episodes