Autor Beitrag
→Tobi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: Sa 07.02.09 21:50 
Ich habe schon versucht ein solches Projekt umzusetzen. Also einen Parser in C#, der eine mathematische Gleichung auflöst. Ich habe zwar schon ein paar Grundkonzepte gefunden, aber noch nicht umsetzen können.

Also ich möchte zuerst die eingeklammerten Ausdrücke suchen. Diese muss ich dann ersetzen. Allerdings weiß ich da schon nicht weiter: Durch was soll ich diese ersetzen? Wie soll ich die ersetzen?

Also wenn ich beispielsweise die Zeichenkette "2 + 3 - (5 + 2)" habe. Ich wäre für einen konkreten Code dankbar.
CarpeDiem
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 128

WIN XP
Borland C++ 2002, CodeGear C++ 2007, C# (VS 2008)
BeitragVerfasst: Sa 07.02.09 22:03 

_________________
Stefan - Carpe Diem
Es ist keine Schande zu fallen, eine Schande ist nur nicht wieder aufzustehen
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 07.02.09 22:04 
Was willst du jetzt eigentlich? Selbst einen Parser schreiben oder einen fertigen Code?
Fertige Parser findest du im Internet viele, z.B. hier:
www.bestcode.com/html/bcparser_net.html
www.codeproject.com/KB/cs/MathParser.aspx
→Tobi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: Sa 07.02.09 23:05 
Also der erste Link hat mir schon geholfen. Vom Verständnis her. Leider ist der Code in Java und ich weiß nicht ob es für jeden Befehl ein Synonym in C# gibt.

Ich möchte eigentlich einen eigenen Parser entwickeln.

Kennt jemand eine Übersicht über die Operatoren und Methoden von Strings?

Edit: Ok. Dumme Frage. Wofür gibts IntelliSense.
→Tobi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: So 08.02.09 12:48 
Weiß jemand wie ich die Zahl vor und nach einem bestimmten Zeichen bestimmen kann, diese einklammere oder etwas in der Art. Zum Beispiel:

( 200 - ( 25 + 15 * 5 ) ) --> ( 200 - ( 25 + ( 15 * 5 ) ) )
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 08.02.09 14:00 
Hab mir den Java-Artikel nicht durchgelesen, aber da müsste das doch behandelt werden?
Wobei die String-Ersetzen-Methode natürlich etwas naiv ist; falls du tiefer in die Materie eintauchen willst, könntest du dir ein Skript anschauen, das user profile iconminiC# vor kurzem gepostet hat: www.itu.dk/people/kfl/parsernotes.pdf (kein Java :mrgreen: )

_________________
>λ=
→Tobi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: So 08.02.09 14:04 
Ich hab schon ne Idee: mit einer Schleife das nächste Zeichen links und rechts vom gesuchten Zeichen suchen und diesen Teil ( zwei Zahlen und ein Zeichen ) einklammern und ausrechnen lassen. Das Suchen nach den beiden Zeichen mach ich wie gesagt mit einer Schleife und einem Vergleich des jeweiligen Zeichens mit einem Array, in dem die definierten Zeichen ( Rechenoperatoren ) enthalten sind.

Alles noch Theorie. Aber ich werds versuchen.

Welchen Namen hat eigentlich die Vorgehensweise dieses Algorithmus?
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 08.02.09 15:13 
user profile icon→Tobi hat folgendes geschrieben Zum zitierten Posting springen:
Welchen Namen hat eigentlich die Vorgehensweise dieses Algorithmus?
Ich glaube nicht, dass es einen gibt. Alle Standardalgorithmen suchen nicht gezielt nach einem Token wie "*", sondern gehen stur von links nach rechts (nämlich LL oder LR) durch die Eingabe. Der einfachste standardmäßige Parser für mathematische Terme ist ein Recursive Descent (bzw. Predictive) Parser, wird wahrscheinlich auch in dem Skript von oben verwendet.

_________________
>λ=
AdrianK
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 56

Kubuntu 9.04 Jaunty
Mono 2.4 + MonoDevelop 2.0; Qt Creator
BeitragVerfasst: So 08.02.09 17:14 
Hallo, ich entwickle gerade auch einen Formelparser in C# und ich hab's so gelöst:
Als erstes wird der Term in eine List<String> aufgeteilt, z.B. so:
ausblenden Quelltext
1:
2:
3+43*5 =
[3][+][4][3][*][5]

Danach werden Zahlen und Kommas zusammengefasst:
ausblenden Quelltext
1:
[3][+][43][*][5]					

Jetzt ist es kein Problem mehr den Term zu berechen, einfach nach allen *, /, + und - suchen und sie berechen. Ungefähr so:
ausblenden C#-Quelltext
1:
2:
3:
4:
int position = term.IndexOf("*");
term[position-1] = Convert.ToString(Convert.ToDouble(term[position-1])*Convert.ToDouble(term[position-1]));
term.RemoveAt(position);
term.RemoveAt(position);

Mit Rekursion sind dann auch Klammern kein Problem mehr. Hoffe ich konnte dir helfen :)
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: So 08.02.09 17:27 
@Adrian
Das Verfahren gefällt mir überhaupt nicht, weil ständig zwischen String und Zahl konvertiert werden muss; beachte außerdem die "zwangsläufigen" Rundungsfehler bei Berechnungen mit double.

Wenn überhaupt, dann sind zwei Listen zu verwenden: List<decimal> mit den Zahlen und List<char> mit den Rechenzeichen und Klammern. Aber vermutlich gibt es in den vielen Links gute/bessere Vorschläge.

Gruß Jürgen
&#8594;Tobi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: So 08.02.09 20:04 
Mhh... Ja, die Idee hatte ich auch schon. Ich war mir nur nicht ganz sicher wie ich dann die drei Elemente im Array durch eines, nämlich das Ergebnis ersetze. Wobei ich natürlich nicht ständig mit diesem Array arbeiten muss. Ich müsste es nur nach jedem Durchgang (zwei Zahlen miteinander verrechnen) neu bilden. Dauert das nicht ziemlich lange?

Wenn nicht: Gute Idee. Wäre einen Versuch wert, vor allem weil es mein erster konkreter Ansatz mit Beispielcode wäre.

Danke.
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: So 08.02.09 21:15 
user profile icon&#8594;Tobi hat folgendes geschrieben Zum zitierten Posting springen:
Ich war mir nur nicht ganz sicher wie ich dann die drei Elemente im Array durch eines, nämlich das Ergebnis ersetze. Wobei ich natürlich nicht ständig mit diesem Array arbeiten muss. Ich müsste es nur nach jedem Durchgang (zwei Zahlen miteinander verrechnen) neu bilden. Dauert das nicht ziemlich lange?

Richtig. Deshalb solltest Du auch keinesfalls Arrays verwenden, sondern List<T>, wo Du jederzeit Elemente entfernen und z.B. 2 Zahlen durch das Ergebnis der aktuellen Teilrechnung ersetzen kannst (genauer: eine Zahl wird durch das Ergebnis ersetzt, die zweite Zahl gestrichen, der Operator in der zweiten Liste ebenfalls).

Jürgen
UGrohne
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Veteran
Beiträge: 5502
Erhaltene Danke: 220

Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
BeitragVerfasst: So 08.02.09 22:12 
Mal ein kleiner Hinweis am Rande: Vor ein paar Tagen bin ich einige C#-Features durchgegangen und da sind mir Ausdrucksbäume aufgefallen. Und ich habe mir so gedacht, dass sich das eventuell eignen würde, einen eigenen Formelparser zu schreiben.

Vielleicht will sich ja mal jmd mit dem Thema beschäftigen und das erruieren?! ;)
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 08.02.09 23:43 
Expression Trees, hach... Ja, da hab ich schon länger etwas geplant :mrgreen: . Projekt Abi hat aber leider erstmal höhere Priorität :( .
Zur Klarstellung: Beim Parsen helfen die nichts. Der große Nutzen liegt im eingebauten LCG[meta]Lightweight Code Generation - DynamicMethod[/meta]-Compiler, mit dem sich ein interessanter kompilierender Matheparser bauen lassen sollte.

_________________
>λ=
UGrohne
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Veteran
Beiträge: 5502
Erhaltene Danke: 220

Windows 8 , Server 2012
D7 Pro, VS.NET 2012 (C#)
BeitragVerfasst: Mo 09.02.09 09:45 
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Expression Trees, hach... Ja, da hab ich schon länger etwas geplant :mrgreen: . Projekt Abi hat aber leider erstmal höhere Priorität :( .
Zur Klarstellung: Beim Parsen helfen die nichts. Der große Nutzen liegt im eingebauten LCG[meta]Lightweight Code Generation - DynamicMethod[/meta]-Compiler, mit dem sich ein interessanter kompilierender Matheparser bauen lassen sollte.

Yapp, genau daran dachte ich nämlich auch ... aber die Zeit ... die fehlt einfach immer :(
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 09.02.09 11:11 
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Der große Nutzen liegt im eingebauten LCG[meta]Lightweight Code Generation - DynamicMethod[/meta]-Compiler, mit dem sich ein interessanter kompilierender Matheparser bauen lassen sollte.
Ja, das geht. Als ich das hier gelesen hatte und MSDN über Expression Trees befragt hatte, habe ich mich vorhin mal drangesetzt und das ausprobiert. Jetzt (2 Stunden später ;-)) habe ich das so weit verstanden und einen Parser hinbekommen, der die Grundrechenarten ohne Klammern oder Punkt vor Strich in einen Expression Tree übersetzt und dann mit verschiedenen Variablenwerten gefüttert werden kann. :mrgreen:
Ich überlege noch wie ich die Variablenwerte einfacher in der GUI einfüttern lassen kann (also variabel was die Anzahl etc. angeht).

Leider fehlen mir noch etliche Kenntnisse in C#, deshalb habe ich ein wenig Probleme mit einer guten Umsetzung. Z.B. wusste ich bis heute Morgen auch nicht was delegates sind, wie ich Eigenschaften genau definiere, usw., aber ich werde im Laufe des Tages vielleicht noch ein wenig Zeit haben da weiter zu basteln und dann das Ergebnis posten. ;-)
AdrianK
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 56

Kubuntu 9.04 Jaunty
Mono 2.4 + MonoDevelop 2.0; Qt Creator
BeitragVerfasst: Mo 09.02.09 17:24 
user profile icon&#8594;Tobi hat folgendes geschrieben Zum zitierten Posting springen:
Mhh... Ja, die Idee hatte ich auch schon. Ich war mir nur nicht ganz sicher wie ich dann die drei Elemente im Array durch eines, nämlich das Ergebnis ersetze. Wobei ich natürlich nicht ständig mit diesem Array arbeiten muss. Ich müsste es nur nach jedem Durchgang (zwei Zahlen miteinander verrechnen) neu bilden. Dauert das nicht ziemlich lange?

Wenn nicht: Gute Idee. Wäre einen Versuch wert, vor allem weil es mein erster konkreter Ansatz mit Beispielcode wäre.

Danke.

Geht nicht sehr lange: einfache Berechnungen auf nem P4 2,4 Ghz (z.B. 3^2,43345+4,345) unter 1ms, kompliziertere mit mehreren klammern etc. so um die 10-30ms.
&#8594;Tobi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: Mo 09.02.09 18:04 
Danke für die vielen guten Antworten.

Also ich denke ich gebe meine Idee mit dem Parser, der nach den Zeichen mit höchster Priorität sucht auch. Der ist doch sehr viel komplizierter zu realisieren als ich dachte. Ich habe es jetzt endlich mit Mühe und Not geschafft eine halbwegs funktionierende Punkt-Vor-Strich-Rechnung zu integrieren. Aber der Code ist bestimmt 300 Zeilen lang und absolut verbugt. Außerdem denke ich, dass die andere Methode effektiver ist (sonst hätte man meine Idee ja schon irgendwann mal umgesetzt ^^).

Also noch mal zusammenfassend:

Ich erzeuge eine Variable Liste mit Strings, die dann nach und nach in das Ergebnis umgeformt wird. Diese Liste geht der Parser durch. Wenn er nun eine öffnende Klammer findet geht fängt er dort erst mal an sie zu lösen. Wenn er eine Buchstabenkette findet, überprüft er ob damit eine Funktion (z.B. Sinus) gemeint ist, oder eine Variable.

Was genau ist so ein LCG-Compiler? Ist der für einen simplen Compiler wichtig? (Ich will überhaupt erst mal einen hinbekommen!^^)

Das ist zwar noch sehr, sehr hochgegriffen - aber wäre es möglich ein Programm zu schreiben, dass eine Formel vereinfacht? Zum Beispiel "225x - 175x + (-45x)". Der Zweck meines Programms ist nämlich einen Graphen zu zeichnen. Und der Parser soll später für ein bestimmtes Intervall die y-Werte in Abhängigkeit von x bestimmen. Da wäre eine verkürzte Formel ja wesentlich effektiver.

Also dann werd ich mal versuchen diese Idee umzusetzen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 09.02.09 18:13 
user profile icon&#8594;Tobi hat folgendes geschrieben Zum zitierten Posting springen:
Was genau ist so ein LCG-Compiler? Ist der für einen simplen Compiler wichtig? (Ich will überhaupt erst mal einen hinbekommen!^^)
Sowas brauchst du nicht, du kannst es auch einfacher machen. ;-)
Und das hat mit dem Parsen auch nichts zu tun sondern danach mit der Auswertung.
AdrianK
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 56

Kubuntu 9.04 Jaunty
Mono 2.4 + MonoDevelop 2.0; Qt Creator
BeitragVerfasst: Mo 09.02.09 18:16 
Das mit dem Sin Cos Tan Rnd etc. kannst du vereinfachen, indem du bevor du irgendwas berechnest die Sinuse usw. durch z.b. S ersetzt. Meinen Parser nutze ich übrigens auch um Graphen zu zeichnen.