[Sourcecode] EasiestEquationParser

  • .NET (FX) 4.5–4.8
  • C#

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von φConst.

    [Sourcecode] EasiestEquationParser

    *Aus dem Sourcecodeaustausch verschoben, da für dort leider unzureichend*

    Hallo liebes Forum,

    eine effiziente und extrem einfache Implementierung eines EquationsParser :

    C#-Quellcode

    1. public static double Calculate(string equation)
    2. {
    3. using (Microsoft.CSharp.CSharpCodeProvider foo = new Microsoft.CSharp.CSharpCodeProvider())
    4. {
    5. var res = foo.CompileAssemblyFromSource(
    6. new System.CodeDom.Compiler.CompilerParameters()
    7. {
    8. GenerateInMemory = false
    9. },
    10. "using System;" +
    11. "public class FooClass { " +
    12. "public double Execute() " +
    13. "{ return (double)" + equation + "; }" +
    14. "}"
    15. );
    16. var type = res.CompiledAssembly.GetType("FooClass");
    17. var obj = Activator.CreateInstance(type, new object[] { });
    18. var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
    19. return (double)output;
    20. }
    21. }


    Aufruf:

    C#-Quellcode

    1. Console.WriteLine(Calculate("15+2*3/1.5*3+2+3*15*16"));
    2. Console.Read();
    3. // Result: 749



    haha
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „φConst“ ()

    Gibt ein Kompromiss:

    C#-Quellcode

    1. public static double Calculate(string equation)
    2. {
    3. using (Microsoft.CSharp.CSharpCodeProvider foo = new Microsoft.CSharp.CSharpCodeProvider())
    4. {
    5. var res = foo.CompileAssemblyFromSource(
    6. new System.CodeDom.Compiler.CompilerParameters()
    7. {
    8. GenerateInMemory = false
    9. },
    10. "using System;" +
    11. "public class FooClass { " +
    12. "public double Execute() " +
    13. "{ return (double)" + equation + "; }" +
    14. "}"
    15. );
    16. if (res.Errors.Count != 0)
    17. throw new Exception((res.Errors[0] +"").Split(new string[] { ": " }, StringSplitOptions.None)[2]);
    18. var type = res.CompiledAssembly.GetType("FooClass");
    19. var obj = Activator.CreateInstance(type, new object[] { });
    20. var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
    21. return (double)output;
    22. }
    23. }


    C#-Quellcode

    1. if (res.Errors.Count != 0)
    2. throw new Exception((res.Errors[0] +"").Split(new string[] { ": " }, StringSplitOptions.None)[2]);


    ( =
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „φConst“ ()

    φConst schrieb:

    Gibt ein Kompromiss
    Die Exception schlägt nicht zu.

    C#-Quellcode

    1. double result = Calculate(this.textBox1.Text);
    2. label1.Text = result.ToString();


    ====
    Teste mal Deine Exception, indem Du nix eingibst.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    1. Equations = Gleichungen. Das sind aber keine Gleichungen, sondern normale Terme. Es handelt sich also eher um einen ExpressionParser.
    2. Ist die Umsetzung halt fragwürdig. Ein Parser sollte mit einem Lexer, Tokens und entsprechenden Algorithmen (ShuntingYard z. B.) arbeiten. Da bietet sich dann eben Potfix-Notation an. Das ist erstens flexibler und zudem kann man das dann auch in einem ExpressionTree etc. anzeigen.
    Edit: Ja, ich weiß, dass Dir das bewusst ist, aber ist halt nunmal so. ^^
    So wird das ganze halt nur via CodeDom so berechnet, als wäre es hardcoded im Quelltext.
    3. Fehlen Funktionen, Konstanten etc.
    Natürlich kann man das mit Math.Sin() etc. mitgeben, aber das ist halt eigentlich Aufgabe des Parsers, das intern zu machen.
    4. Wie Mokki bereits erwähnt hat, ist das halt auch sicherhektstechnisch nicht gerade optimal.
    5. Kannst Du das Behandeln von falschen Termen somit, wie schon angemerkt, vergessen.

    Un ehrlich zu sein, die Idee ist wirklich originell, aber so leicht klappt's halt dann doch nicht. :(

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ ()

    Es gibt aber auch einiges zugute zu halten: Nämlich dass einen FormelParser zu basteln eine sehr anscpruchsvolle und sehr umfangreiche Aufgabe ist.
    Und fahren viele "Formalparser" im INet rum, die schlicht und ergreifend nicht richtig rechnen - spätestens, wenns an Operator-Vorränge und Klammersetzung geht.
    Ich mein Commandinjection wird immer durch whitelisting/blacklisting behoben. In dem Fall würde ich aber auf jeden Fall whitelisting nehmen. Das Ganze ist nur nen ziehmlich heißes Eisen, wenn man bedenkt wieviele Möglichkeiten man hat in .Net Code zu schreiben... aber es ist dann zumindest einigermaßen sicher...

    Lg Mokki
    ​Smartnotr - ein intelligentes Notizprogramm
    zum Thread

    @ErfinderDesRades Naja, es geht. Natürlich hat das alles seine Grenzen oder wird halt ab einem bestimmten Punkt ziemlich kompliziert, was das ganze hinter dem Term angeht. Aber mit Deinen Tutorials und etwas Recherche kann man da durchaus was basteln.
    Hab ich darauf basierend auch schon gemacht: github.com/ProgTrade/SharpMath…ter/SharpMath/Expressions
    Klar, braucht etwas Einarbeitung, aber dann ist rine mögliche Unsetzung auch kein Hexenwerk mehr. Habe das dann auch mal in Swift umgesetzt, wo es ebenso wunderbar funktioniert. :)
    Und damkt könnte man eben noch vieles mehr anstellen und hat zugleich eben auch ordentliches Fehlerhandling.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    haha, danke für den Feedback.
    Es war nie meine Intention diese Idee als professionelles Konzept zu propagieren(gibt es ja schon: ShuntingYard) ; der Beitrag hat - gekennzeichnet durch das "haha" am Ende des Beitrags - eher einen
    satirischen Charakter.
    Es sollte euch unterhalten ^^

    Liebe Grüße ( =


    Und Gott alleine weiß alles am allerbesten und besser.