Frage

    

Diese Frage bereits eine Antwort hier:

         

Gibt es eine Funktion der .NET-Framework, das einen numerischen Ausdruck, die in einem String auswerten und das Ergebnis zurück? F.e:.

string mystring = "3*(2+4)";
int result = EvaluateExpression(mystring);
Console.Writeln(result); // Outputs 18

Gibt es eine Standard-Framework-Funktion, die Sie meine EvaluateExpression Methode mit ersetzen können?

War es hilfreich?

Lösung

Ja, können Sie C # Compiler lassen Sie es zur Laufzeit zu bewerten.

Siehe auch: CSharpCorner

Andere Tipps

Wenn Sie ein String-Ausdruck bewerten den folgenden Code-Schnipsel verwenden.

using System.Data;

DataTable dt = new DataTable();
var v = dt.Compute("3 * (2+4)","");

, um den Compiler zu impliziert Lecks Speicher zu tun, wie die erzeugten Baugruppen geladen werden und nie veröffentlicht. Es ist auch weniger performant als einen echten Ausdruck Interpreter. Zu diesem Zweck können Sie verwenden Ncalc Das ist eine Open-Source-Framework mit dieser ausschließlich Absicht. Sie können auch Ihre eigenen Variablen und benutzerdefinierte Funktionen definieren, wenn die, die bereits enthalten sind nicht genug.

Beispiel:

Expression e = new Expression("2 + 3 * 5");
Debug.Assert(17 == e.Evaluate());

Versuchen Sie folgendes:

static double Evaluate(string expression) {
  var loDataTable = new DataTable();
  var loDataColumn = new DataColumn("Eval", typeof (double), expression);
  loDataTable.Columns.Add(loDataColumn);
  loDataTable.Rows.Add(0);
  return (double) (loDataTable.Rows[0]["Eval"]);
}

Sie bei „XpathNavigator.Evaluate“ aussehen könnte, die ich verwendet habe diese mathematische Ausdrücke für meine Gridview zu verarbeiten und es funktioniert gut für mich.

Hier ist der Code, den ich für mein Programm verwendet:

public static double Evaluate(string expression)
{
    return (double)new System.Xml.XPath.XPathDocument
    (new StringReader("<r/>")).CreateNavigator().Evaluate
    (string.Format("number({0})", new
    System.Text.RegularExpressions.Regex(@"([\+\-\*])")
    .Replace(expression, " ${1} ")
    .Replace("/", " div ")
    .Replace("%", " mod ")));
}
static double Evaluate(string expression) { 
  var loDataTable = new DataTable(); 
  var loDataColumn = new DataColumn("Eval", typeof (double), expression); 
  loDataTable.Columns.Add(loDataColumn); 
  loDataTable.Rows.Add(0); 
  return (double) (loDataTable.Rows[0]["Eval"]); 
} 

Erklärung, wie es funktioniert:

Als erstes machen wir einen Tisch im Teil var loDataTable = new DataTable();, genau wie in einem Datenbank-Engine (MS SQL zum Beispiel).

Dann wird eine Spalte mit einigen spezifischen Parametern (var loDataColumn = new DataColumn("Eval", typeof (double), expression);).

Der "Eval" Parameter ist der Name der Spalte (Spaltenname-Attribut).

typeof (double) ist die Art der Daten in der Spalte gespeichert werden, die stattdessen setzen System.Type.GetType("System.Double"); gleich ist.

expression ist der String, der Evaluate Methode empfängt, und wird in dem Attribut Expression der Säule gespeichert. Dieses Attribut ist für einen wirklich besonderen Zweck (offensichtlich), das ist, dass jede Zeile, die auf der Säule gegeben ist wird mit der „Expression“ erfüllt werden, und es nimmt praktisch wathever kann in einer SQL-Abfrage gestellt werden. Siehe http: / /msdn.microsoft.com/en-us/library/system.data.datacolumn.expression(v=vs.100).aspx zu wissen, was in dem Expression-Attribute gesetzt werden kann, und wie sie ausgewertet werden.

Dann loDataTable.Columns.Add(loDataColumn); fügt die Spalte loDataColumn zur loDataTable Tabelle.

Dann wird eine Zeile in die Tabelle mit einer personalisierten Säule mit einem Ausdruck Attribute hinzugefügt, über loDataTable.Rows.Add(0); getan. Wenn wir diese Zeile hinzufügen, wird die Zelle der Spalte „Eval“ der Tabelle loDataTable automatisch mit seinem „Expression“ Attribute erfüllt, und, wenn es Betreiber und SQL-Abfragen hat, usw., wird es ausgewertet und dann in der Zelle gespeichert, so hier geschieht die „Magie“, wird die Zeichenfolge mit den Betreibern zu einer Zelle ausgewertet und gespeichert ...

Schließlich kehrt nur die an der Zelle der Spalte „Eval“ in Zeile gespeicherten Wert 0 (es ist ein Index, beginnt ein Zählen von Null), und eine Umwandlung in eine Doppel mit return (double) (loDataTable.Rows[0]["Eval"]); machen.

Und das ist alles ... fertig!

Und hier ein Code eaiser zu verstehen, was das gleiche tut ... Es ist nicht innerhalb einer Methode, und es wird auch erklärt.

DataTable MyTable = new DataTable();
DataColumn MyColumn = new DataColumn();
MyColumn.ColumnName = "MyColumn";
MyColumn.Expression = "5+5/5"
MyColumn.DataType = typeof(double);
MyTable.Columns.Add(MyColumn);
DataRow MyRow = MyTable.NewRow();
MyTable.Rows.Add(MyRow);
return (double)(MyTable.Rows[0]["MyColumn"]);

Erstellen Sie zunächst die Tabelle mit DataTable MyTable = new DataTable();

Dann wird eine Spalte mit DataColumn MyColumn = new DataColumn();

Als nächstes setzten wir einen Namen für die Spalte. Das können wir so suchen hinein Inhalt ist, wenn es auf die Tabelle gespeichert ist. Geschehen über MyColumn.ColumnName = "MyColumn";

Dann wird der Ausdruck, hier können wir eine Variable vom Typ String setzen, in diesem Fall gibt es eine vordefinierte Zeichenfolge "5 + 5/5", das Ergebnis ist 6.

Die Art der Daten in die Spalte MyColumn.DataType = typeof(double); gespeichert werden

Fügen Sie die Spalte der Tabelle ... MyTable.Columns.Add(MyColumn);

Erstellen Sie eine Zeile in die Tabelle eingefügt werden, die Kopien der Tabellenstruktur DataRow MyRow = MyTable.NewRow();

Fügen Sie die Zeile in die Tabelle mit MyTable.Rows.Add(MyRow);

Und gibt den Wert der Zelle in der Zeile 0 der Spalte MyColumn der Tabelle MyTable mit return (double)(MyTable.Rows[0]["MyColumn"]);

Lektion gemacht !!!

Dies ist ein einfacher Ausdruck Evaluator Stacks

public class MathEvaluator
{
    public static void Run()
    {
        Eval("(1+2)");
        Eval("5*4/2");
        Eval("((3+5)-6)");
    }

    public static void Eval(string input)
    {
        var ans = Evaluate(input);
        Console.WriteLine(input + " = " + ans);
    }

    public static double Evaluate(String input)
    {
        String expr = "(" + input + ")";
        Stack<String> ops = new Stack<String>();
        Stack<Double> vals = new Stack<Double>();

        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            if (s.Equals("(")){}
            else if (s.Equals("+")) ops.Push(s);
            else if (s.Equals("-")) ops.Push(s);
            else if (s.Equals("*")) ops.Push(s);
            else if (s.Equals("/")) ops.Push(s);
            else if (s.Equals("sqrt")) ops.Push(s);
            else if (s.Equals(")"))
            {
                int count = ops.Count;
                while (count > 0)
                {
                    String op = ops.Pop();
                    double v = vals.Pop();
                    if (op.Equals("+")) v = vals.Pop() + v;
                    else if (op.Equals("-")) v = vals.Pop() - v;
                    else if (op.Equals("*")) v = vals.Pop()*v;
                    else if (op.Equals("/")) v = vals.Pop()/v;
                    else if (op.Equals("sqrt")) v = Math.Sqrt(v);
                    vals.Push(v);

                    count--;
                }
            }
            else vals.Push(Double.Parse(s));
        }
        return vals.Pop();
    }
}

Dies ist von rechts nach links Ausführung, so müssen geeignete parathesis verwendet Ausdruck auszuführen

    // 2+(100/5)+10 = 32
    //((2.5+10)/5)+2.5 = 5
    // (2.5+10)/5+2.5 = 1.6666
    public static double Evaluate(String expr)
    {

        Stack<String> stack = new Stack<String>();

        string value = "";
        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            char chr = s.ToCharArray()[0];

            if (!char.IsDigit(chr) && chr != '.' && value != "")
            {
                stack.Push(value);
                value = "";
            }

            if (s.Equals("(")) {

                string innerExp = "";
                i++; //Fetch Next Character
                int bracketCount=0;
                for (; i < expr.Length; i++)
                {
                    s = expr.Substring(i, 1);

                    if (s.Equals("("))
                        bracketCount++;

                    if (s.Equals(")"))
                        if (bracketCount == 0)
                            break;
                        else
                            bracketCount--;


                    innerExp += s;
                }

                stack.Push(Evaluate(innerExp).ToString());

            }
            else if (s.Equals("+")) stack.Push(s);
            else if (s.Equals("-")) stack.Push(s);
            else if (s.Equals("*")) stack.Push(s);
            else if (s.Equals("/")) stack.Push(s);
            else if (s.Equals("sqrt")) stack.Push(s);
            else if (s.Equals(")"))
            {
            }
            else if (char.IsDigit(chr) || chr == '.')
            {
                value += s;

                if (value.Split('.').Length > 2)
                    throw new Exception("Invalid decimal.");

                if (i == (expr.Length - 1))
                    stack.Push(value);

            }
            else
                throw new Exception("Invalid character.");

        }


        double result = 0;
        while (stack.Count >= 3)
        {

            double right = Convert.ToDouble(stack.Pop());
            string op = stack.Pop();
            double left = Convert.ToDouble(stack.Pop());

            if (op == "+") result = left + right;
            else if (op == "+") result = left + right;
            else if (op == "-") result = left - right;
            else if (op == "*") result = left * right;
            else if (op == "/") result = left / right;

            stack.Push(result.ToString());
        }


        return Convert.ToDouble(stack.Pop());
    }

Sie können ziemlich leicht laufen diese durch die CSharpCodeProvider mit geeigneten Flaum es Einwickeln (eine Art und ein Verfahren, im Grunde). Ebenso könnte man durch VB gehen usw. - oder JavaScript, als eine andere Antwort vorgeschlagen hat. Ich weiß nichts anderes mehr in den Rahmen an dieser Stelle gebaut.

Ich würde erwarten, dass .NET 4.0 mit Unterstützung für dynamische Sprachen und bessere Fähigkeiten an dieser Front hat.

Vor kurzem habe ich benötigt, um dies für ein Projekt zu tun, und ich landete mit Ironpython, es zu tun. Sie können eine Instanz des Motors, erklären und dann jeden gültigen Python Ausdruck übergeben und das Ergebnis erhalten. Wenn Sie nur einfache mathematische Ausdrücke zu tun, dann würde es ausreichen. Mein Code am Ende der Suche ähnelt:

IronPython.Hosting.PythonEngine pythonEngine = new IronPython.Hosting.PythonEngine();
string expression = "3*(2+4)";
double result = pythonEngine.EvaluateAs<double>(expression);

Sie möchten sicher nicht den Motor für jeden Ausdruck erstellen. Sie müssen auch einen Verweis auf IronPython.dll

EDIT:. Realisierte ich wirklich die Zugabe bringen sollte und Subtraktion separat als gut, um es ein bisschen zu machen mehr BODMAS konform

Vielen Dank an Rajesh Jinaga für seinen Stack-basierten Ansatz. Ich fand es für meine Bedürfnisse wirklich nützlich. Der folgende Code eine leichte Modifikation von Rajesh Methode ist, die ersten Teilungen verarbeitet, dann Multiplikationen, endet dann mit Addition und Subtraktion auf. Es wird auch die Verwendung von booleans in der Ausdrücken erlauben, wo wahr als 1 und falsch 0 behandelt wird, um die Verwendung von Booleschen Logik in Ausdrücken erlaubt.

public static double Evaluate(string expr)
    {
        expr = expr.ToLower();
        expr = expr.Replace(" ", "");
        expr = expr.Replace("true", "1");
        expr = expr.Replace("false", "0");

        Stack<String> stack = new Stack<String>();

        string value = "";
        for (int i = 0; i < expr.Length; i++)
        {
            String s = expr.Substring(i, 1);
            // pick up any doublelogical operators first.
            if (i < expr.Length - 1)
            {
                String op = expr.Substring(i, 2);
                if (op == "<=" || op == ">=" || op == "==")
                {
                    stack.Push(value);
                    value = "";
                    stack.Push(op);
                    i++;
                    continue;
                }
            }

            char chr = s.ToCharArray()[0];

            if (!char.IsDigit(chr) && chr != '.' && value != "")
            {
                stack.Push(value);
                value = "";
            }
            if (s.Equals("("))
            {
                string innerExp = "";
                i++; //Fetch Next Character
                int bracketCount = 0;
                for (; i < expr.Length; i++)
                {
                    s = expr.Substring(i, 1);

                    if (s.Equals("(")) bracketCount++;

                    if (s.Equals(")"))
                    {
                        if (bracketCount == 0) break;
                        bracketCount--;
                    }
                    innerExp += s;
                }
                stack.Push(Evaluate(innerExp).ToString());
            }
            else if (s.Equals("+") ||
                     s.Equals("-") ||
                     s.Equals("*") ||
                     s.Equals("/") ||
                     s.Equals("<") ||
                     s.Equals(">"))
            {
                stack.Push(s);
            }
            else if (char.IsDigit(chr) || chr == '.')
            {
                value += s;

                if (value.Split('.').Length > 2)
                    throw new Exception("Invalid decimal.");

                if (i == (expr.Length - 1))
                    stack.Push(value);

            }
            else
            {
                throw new Exception("Invalid character.");
            }

        }
        double result = 0;
        List<String> list = stack.ToList<String>();
        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "/")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) / Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }

        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "*")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) * Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }
        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "+")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) + Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }
        for (int i = list.Count - 2; i >= 0; i--)
        {
            if (list[i] == "-")
            {
                list[i] = (Convert.ToDouble(list[i - 1]) - Convert.ToDouble(list[i + 1])).ToString();
                list.RemoveAt(i + 1);
                list.RemoveAt(i - 1);
                i -= 2;
            }
        }
        stack.Clear();
        for (int i = 0; i < list.Count; i++)
        {
            stack.Push(list[i]);
        }
        while (stack.Count >= 3)
        {
            double right = Convert.ToDouble(stack.Pop());
            string op = stack.Pop();
            double left = Convert.ToDouble(stack.Pop());

            if (op == "<") result = (left < right) ? 1 : 0;
            else if (op == ">") result = (left > right) ? 1 : 0;
            else if (op == "<=") result = (left <= right) ? 1 : 0;
            else if (op == ">=") result = (left >= right) ? 1 : 0;
            else if (op == "==") result = (left == right) ? 1 : 0;

            stack.Push(result.ToString());
        }
        return Convert.ToDouble(stack.Pop());
    }

Ich weiß, es ist wahrscheinlich eine sauberere Art und Weise zu tun, es sein, dachte id nur es bei dem ersten Blick teilt jemand findet es sehr nützlich.

Vielen Dank an Ramesh. Früher habe ich eine Version seines einfachen Code eine Zeichenfolge aus einer Datenbank zu ziehen, und es verwendet, Boolesche Operationen in meinem Code zu tun.

x ist eine Zahl wie 1500 oder 2100 oder was auch immer.

Funktion wäre eine gespeicherte Auswertung wie x> 1400 und x <1600

function = relation[0].Replace("and","&&").Replace("x",x);

DataTable f_dt = new DataTable();
var f_var = f_dt.Compute(function,"");

if (bool.Parse(f_var.ToString()) { do stuff  }

Es gibt nicht. Sie müssen einige externe Bibliothek verwenden, oder Ihren eigenen Parser schreiben. Wenn Sie die Zeit haben, dies zu tun, schlage ich vor Ihrem eigenen Parser zu schreiben, wie es ein ziemlich interessantes Projekt ist. Andernfalls müssen Sie etwas verwenden, wie bcParser .

Kurze Antwort: Ich glaube nicht. C # .NET kompiliert (Bytecode) und kann keine Strings zur Laufzeit auswerten, soweit ich weiß. JScript .Net können jedoch; aber ich würde Sie noch raten, einen Parser zu codieren und Stack-basiertes Auswertungsprogramm selbst.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top