![]() |
Term (Zeichenfolge 1+2*3) in Fließkommazahl
Hallo, ich mache gerade für die Schule einen Taschenrechner und habe ihn auch vom optischen her fertig.
Eingabebuttons für Zahlen, Zeichen und ein Rechenfeld. Wenn man jetzt 1+2*3 eingibt, was ja 7 ergibt, soll eine String Variable rTerm auf ('1+2*3') gesetzt werden. Soweit kein Problem. Jetzt kommt der Button "Gleich" ins Spiel. Er soll die Variable rErgebnis : real auf das Ergebnis des Terms setzen, also erst ausrechnen, dann StrToFloat. Hier ist das Problem. Dann will ich das Ergebnis noch ausgeben, das krieg ich aber auch hin.
Delphi-Quellcode:
:coder2:
procedure TForm1.ButtonGleichClick(Sender: TObject);
begin rZahl:=StrToFloat(rTerm); Edit1.text:=FloatToStr(rZahl); end; So klappts ja nicht, habs nur mal probiert. Da Delphi aber Punkt vor Strich rechnet, wollte ich das auf diese Art machen. Bitte helft mit, Liebe Grüße! |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Tjaa...
Da musst du dir wohl einen Parser basteln, der dir deinen String zerlegt. So einfach wird das nicht funktionieren. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Was dir hier noch fehlt, ist ein Formelinterpreter und der geht über die Aufgabe "Taschenrechner" deutlich hinaus. Ich empfehle dir einen anderen Ansatz, der die Berechnungen gleich beim Tastendruck ausführt - so macht es der Taschenrechner nämlich auch. Übrigens bekommt der bei der Eingabe "1+2*3=" eine 9 heraus, während ein Formelinterpreter eine 7 auswerfen würde.
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Du kannst mit StrToFloat keinen Term in eine Gleitkommazahl umwandeln. Diese Funktion ist ausschließlich dafür da, eine Kommazahl, welche als Zeichenkette gespeichert ist, in eine Gleitkommazahl umzuwandeln. Für das was du vorhast, benötigst du einen Parser, der den String analysiert und dann die Berechnung durchführt, aber sowas zu programmieren ist alles andere als trivial.
Du solltest dir eher in einer Liste oder einer anderen dafür geeigneten Struktur, die Zahlen und Operatoren merken und diese dann im nachhinein mit den Rechenregeln zusammen rechnen. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Danke für die vielen schnellen Antworten. :thumb:
Der "Taschenrechner" (Ergebnis=9) ist Pflicht, es gibt halt Bonuspunkte für den Rechner, der den String erst ausrechnet... In meiner Gruppe wollen wir halt einen Termberechner machen, der also auch Klammern etc. berechnet. Es wäre ja auch Möglich, das Ganze mit den Variablen Zahl1 (=1) dann dem Zeichen1 (=+ -> Als 1 gespeichert -> if Zeichen1=1 then +...) und dann wieder Zeichen usw. Dafür müssten nur genug Variablen vorhanden sein. Gibt es die Möglichkeit, diese Variablen dann automatisch je nach Bedarf erstellen zu lassen? Ich starte mit rZahl1, rZeichen1 und rZahl2. Wenn dann noch was eingegeben wird, soll rZeichen2 automatisch erstellt werden. Dann beim Gleich Button: Zahlen sortieren und Zeichen sortieren, nach Name und dann immer abwechselnd anordnen. Zahl,Zeichen,Zahl usw. Das Ergebnis wird dann so berechnet... Auch möglich??? |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Wie gesagt, wäre dafür eine Liste sehr praktisch. Allerdings wird für eine einigermaßen gute Implementierung schon ein gewisses Grundverständnis der OOP vorrausgesetzt und ich vermute mal, dass dies bei dir nicht der Fall ist. Und dir jetzt hier einen Code vorzuwerfen, der das erledigt möchte ich auch nicht, da es sich ja um eine Schulaufgabe handelt und du etwas lernen sollst.
Es gäbe noch die Möglichkeit, dass du das ganze über eine TStringList versuchst, was dann doch etwas einfacher für dich sein sollte, aber auch keine tolle Lösung ist. Schau dich einfach mal im Forum um, wie man eine TStringList verwendet und falls du nicht weiter weißt, frag einfach nochmal. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
jupp, um einen Parser kommst du da nicht drumrum
Zitat:
z.B. erstmal alles in seine einzelteile zerlegen und in ein Array damit
Code:
und dann nach den gängigen mathematischen Regeln nacheinander versuchen dieses aufzuösen
1
+ 2 * 3 hier z.B. zuerst * und dann + also erstmal ein "*" suchen, wo davor und danach eine Zahl vorkommt dieses nun ausrechnen und ersetzen
Code:
nun das Gleiche mit dem "+"
1
+ 6 praktisch immer zuerst * und / versuchen aufzulösen, dann + und - und zuletzt + mit nur einer Zahl dahinter immer von vorne nach hinten entsprechende Gruppen (Zahl-Operator-Zahl) suchen und wenn etwas gefunden wurde, dieses ausrechnen und ersetzen, dann erneut von vorne ganz vorner im Array anfangen das nächste zu finden und das solange, bis nichts mehr zum Auflösen gefunden wurde * String in Array zerlegen > je Zahlen und Operatoren pro Eintrag * wiederhole: * nach "zahl*zahl" suchen * - dieses ausrechnen und ersetzen und weiter bei "wiederhole" * nach "zahl/zahl" suchen * - dieses ausrechnen und ersetzen und weiter bei "wiederhole" * nach "zahl+zahl" suchen * - dieses ausrechnen und ersetzen und weiter bei "wiederhole" * nach "zahl-zahl" suchen * - dieses ausrechnen und ersetzen und weiter bei "wiederhole" * nach "+zahl" suchen * - dieses zusammensetzen und ersetzen und weiter bei "wiederhole" * nach "-zahl" suchen * - dieses zusammensetzen und ersetzen und weiter bei "wiederhole" * Array wieder zum Strng zusammensetzen und ausgeben * - also einfach alles aneinanderhängen mit viel Glück ist dann am Ende nur noch ein Eintrag mit einer Zahl übrig und wenn nicht, dann paßte etwas in der "Formel" nicht ganz [edit] jupp, statt dem Array macht sich wohl eine StringListe hier icht schlecht, da man dort leichter Einträge entfernen kann. [/edit] PS: ![]() siehe Demo5 und Demo6 auch wenn es dir wohl nnicht viel Helfen wird, aber immerhin ist der QuellCode ja offen und vielleicht findet du in dem Parser ja ein/zwei Anregungen. macht mein Parser nicht viel anders - nur daß ich da noch Klammern, Funktionen und Anderes mit drin hab ... nja und halt mit anderen Zahlenstrukturen rechne |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Sieht gut aus, danke.
Delphi berechnet ja theoretisch: rZahl:=1+2*3 Dann ist rZahl=7 Darum müsste man dem doch nur klar machen, dass der die Formel, die in rTerm steckt, berechnen soll. ___________________ Wie zerlege ich sowas denn? |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Delphi berechnet nichts.
Im Compiler ist ein Parser, welcher den Quelltext zerlegt und es dann in der EXE sozusagen in der EXE schon richtig zusammengesetzt eingebaut hat. Da der Parser nur in dem Compiler drin ist, kannst du diesen nicht in der EXE nutzen und mußt dir einen Eigenen bauen (oder einen Fertigen von wo anders verwenden) |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Oh...
Dann muss ich halt den Term zerlegen und die Zeichen suchen, wie beschrieben - nur wie??? |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
Zitat:
Delphi-Quellcode:
Weiterhin wären vielleicht noch die Befehle Copy und Pos hierfür interessant.
S[1] // greift auf das erste Zeichen im String S zu
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
wo kommt denn die andere Antwort plötzlich her? OK, hab zufällig ihn auch immer auf Wissenschaftlich stehen :angel2: |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Danke, ich habe noch nicht sooo viel Ahnung. Also wenn ich jetzt rTerm[1] und der Term ist 1+2*3 dann würde der die 1 wählen???
Dann muss ich noch wissen, was ist, wenn im Term steht, 12+3 Der soll ja dann auf zwei Zeichen zugreifen... |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Ich hoffe, dass du schon mal was von Schleifen gehört hast, besonders von for-Schleifen, denn diese wirst du hier benötigen. Du läufst also mit Hilfe der for-Schleife durch den String durch und prüfst, ob das aktuelle Zeichen ein Operator ist. Wenn dies der Fall ist, dann fügst du die Zeichen zwischen diesem Operator und dem letzten Operator bzw. dem Start, hierfür solltest du dir die Positon in einer extra Variablen merken, in deine StringListe ein, hierfür ist der Befehl Copy sehr nützlich. Außerdem musst du noch den Operator in die Stringliste einfügen, das geht ja recht einfach, da du die Position davon sowieso grad weißt. Jetzt noch die Position des aktuellen Operators merken und dann geht das ganze wieder von vorn los.
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Liste der Anhänge anzeigen (Anzahl: 3)
Das Parsen ist recht einfach ... wie es schon genannt wurde, kann man einfach von vorn nach hinten Zeichen für Zeichen durchgehn und sie entsprechend ihrem Typ (Zahl oder Operator) auf ein Array oder eine StringListe aufteilen.
Ein etwas effektiverer Weg mittels Copy steckt in dem ebenfalls schon verlinkten MatheParser, aber die Geschwindigkeit der Einzelzeichenbehandlung ist für diesen Zweck hier auch vollkommend ausreichend.
Delphi-Quellcode:
Die ZIP enthält die EXE und den wie hier gekürzten QuellCode.
Function ParseAndCalc(Const S: String): String;
Var SL: TStringList; i: Integer; Begin SL := TStringList.Create; Try Try SL.Add(''); For i := 1 to Length(S) do Case S[i] of '0'..'9', ',', '.': Begin SL[SL.Count - 1] := SL[SL.Count - 1] + S[i]; End; '*', '/', '+', '-': Begin If SL[SL.Count - 1] = '' Then Begin // eine leere Zeile kommt vor, wenn mehrere Operatoren // hintereinander liegen, z.B. bei '1*+2' bzw. '1 * +2' SL.Delete(SL.Count - 1); End; SL.Add(S[i]); SL.Add(''); End; ' ': ; // ignoriere Leerzeichen Else Raise Exception.CreateFmt('Ungültiges Zeichen "%s" gefunden.', [S[i]]); End; // hier alles in SL ausrechnen Finally Result := ''; For i := 0 to SL.Count - 1 do Result := Result + SL[i]; End; Finally SL.Free; End; End; Procedure TForm1.Button1Click(Sender: TObject); Begin Edit2.Text := ParseAndCalc(Edit1.Text); End; In der passwortgeschützen 7-Zip steckt der komplette Code. Das Paswort gebe ich gern an nicht Schüler und andere Interessenten raus, wo ich das Gefühl hab, daß sie es nicht als Hausaufgabenlösung mißbrauchen. PS: Es sind da auch nur 64 zusätzliche Zeilen mit je 7-8 Zeilen pro Operator (+ - * / und den Vorzeichen + -). und zum Ausprobieren kennt die Demo also diese Operatoren und den Dezimalpunkt (deutsches Windows = "," und englisches Windows = "."), so wie es halt von StrToFloat behandelt wird. Wie es ausgerechnet hab ich oben erklärt und es wird einfach nur nacheinander je Operator in einer For-Schleife geschaut ob der Operator vorhanden und berechenbar ist und dann wird wie oben beschrieben vorgegangen. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
bevor ich's noch vergesse ... das höchst geheime Paßwort ist
Zitat:
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Danke! Also von Schleifen hab ich gehört, klar...
Ich bau das dann mal ein... :bounce1: Edit:
Delphi-Quellcode:
procedure TForm1.ButtonGleichClick(Sender: TObject);
begin Ausgabefeld.text:=ParseandCalc(Rechenfeld.text); end; //Hier der Parser Function TForm1.ParseAndCalc(Const S: String): String; Var SL: TStringList; i: Integer; Begin SL := TStringList.Create; Try Try SL.Add(''); For i := 1 to Length(S) do Case S[i] of '0'..'9', ',', '.': Begin SL[SL.Count - 1] := SL[SL.Count - 1] + S[i]; End; '*', '/', '+', '-': Begin If SL[SL.Count - 1] = '' Then Begin // eine leere Zeile kommt vor, wenn mehrere Operatoren // hintereinander liegen, z.B. bei '1*+2' bzw. '1 * +2' SL.Delete(SL.Count - 1); End; SL.Add(S[i]); SL.Add(''); End; ' ': ; // ignoriere Leerzeichen Else Raise Exception.CreateFmt('Ungültiges Zeichen "%s" gefunden.', [S[i]]); End; // hier alles in SL ausrechnen Finally Result := ''; For i := 0 to SL.Count - 1 do Result := Result + SL[i]; End; Finally SL.Free; End; End; Aber wenn ich dann jetzt bspw. 124+2 eingebe steht im Ausgabefeld ebenfalls 124+2 und nicht 126 Könnte das an
Delphi-Quellcode:
liegen? Ich dachte das wäre bei Delphi 5 sysUtils...
Uses StrUtils;
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Ich habe gerade auf Delphi-Treff gesehen, dass dort ein Funktionsinterpreter für einen Taschenrechner in Form eines Tutorials gebaut wird... Vielleicht hilft das ja noch ein bisschen weiter ->
![]() |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Nein, das liegt daran, daß du die letzen beiden Beiträge nicht richtig gelesen hast.
Der Quellcode ist unvollständig und muss von dir an dieser Stelle ergänzt werden: // hier alles in SL ausrechnen Wenn du tatsächlich verstehst, was in dem kopierten Quellcode passiert, dürfte das kein Problem sein. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Ich hatte mir diese Lösung runtergeladen, da fehlte das auch... Konnte das nur wegen StrUtils nicht kompilieren...
Also so ganz richtig versteh ich das nicht. :( |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Na, dann musst Du Dir doch die Frage stellen, was SL (oder meinetwegen auch ein Element daraus) eigentlich ist.
Wenn Du die Antwort dazu hast kanns weiter gehen. Sherlock |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
Delphi-Quellcode:
in dem kompletten Code steht dann z.B. sowas drin
For i := 0 to SL.Count - 3 do
If TryStrToFloat(SL[i], a) and (SL[i + 1] = '*') and TryStrToFloat(SL[i + 2], b) Then Begin SL.Delete(i); SL.Delete(i); SL[i] := FloatToStr(a * b); Goto Loop; End; dieses schaut, ob irgendwo in SL eine Kombination von "Zahl * Zahl" vorkommt
Delphi-Quellcode:
wenn soetwas gefunden wurde, dann wird dieses ausgerechnet und in SL durch das Ergebnis ersetzt
If TryStrToFloat(SL[i], a)
and (SL[i + 1] = '*') and TryStrToFloat(SL[i + 2], b) Then Begin
Delphi-Quellcode:
es geht auch andersrum
SL.Delete(i + 2);
SL.Delete(i + 1); SL.Delete(i); SL.Insert(i, FloatToStr(a * b));
Delphi-Quellcode:
etwas gekürzter Austausch
SL.Insert(i, FloatToStr(a * b));
SL.Delete(i + 1); SL.Delete(i + 2); SL.Delete(i + 3); // bzw. SL.Insert(i + 3, FloatToStr(a * b)); SL.Delete(i + 2); SL.Delete(i + 1); SL.Delete(i);
Delphi-Quellcode:
und noch mehr gekürzt
SL.Delete(i);
SL.Delete(i); SL.Delete(i); SL.Insert(i, FloatToStr(a * b));
Delphi-Quellcode:
nja, jedenfalls müssen irgendwie aus der Liste die entsprechenden (hierfür 3) Einträge raus
SL.Delete(i);
SL.Delete(i); SL[i] := FloatToStr(a * b); und dafür das Ergebnis rein Zitat:
Zitat:
Wegen was bezüglich der StrUtils konnte es nicht kompiliert werden? (eine "richtige" Fehlermeldung) Und welche Delphi-Version hattest du nochmal? gut, das mit dem Delphi 5 hat sich ja grade geklärt. ja, dann mußt du einfach diese Unit entfernen und dann schauen bei welchen Funktionen das Delphi nun meckert, weil es diese nicht kennt .... dann könnte man nachsehn ob passende Funktionen irgendwo in D5 existieren oder man sorgt irgendwie für Ersatz. (Ersatzfunktion basteln oder das Problem anders lösen) [add] ohne die StrUtils könnte man statt
Delphi-Quellcode:
einfach dieses machen
AnsiMatchText(SL[i - 1], ['*', '/', '+', '-'])
Delphi-Quellcode:
((SL[i - 1] = '*') or (SL[i - 1] = '/') or (SL[i - 1] = '+') or (SL[i - 1] = '-'))
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Danke für die Antwort. Ich habs auch kompiliert gekriegt, nachdem ich etwas geändert habe...
Ich les mir das und die 7zip mal genau durch... |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
Delphi-Quellcode:
oder
SL[i-1] in ['*','/','+','-']
Delphi-Quellcode:
:stupid:
Pos('*/+-',SL[i-1])<>0
Dein Code kann aber keine Klammern, oder? Ich hab hier was.... [edit]Code entfernt, da er nicht richtig funktioniert[/edit] [edit]Verbesserten Code am Ende eingefügt[/edit] |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
hatte es nur so gelößt, damit man dann auch noch "mod" und Co. einfach nachrüsten kann :angel: (wie hier unten die Klammern, beim Zerlegen, reingequetscht werden, braucht man nur 'a'..'z', 'A'..'Z' bei den Zahlen reinmachen und hat auch noch Wörter, wie Named-Operators, mit geparst ) Zitat:
- einmal als Vorzeichen ganz am Anfang, da höchste Priorität - und nochmal ganz am Ende als Operator, da niedrigste Priorität nein, der kann noch keine Klammern das hier sollte "nur" ein kleiner "einfacher" Anfang werden, nicht so wie da ![]() man müßte nur noch "(" und ")" beim Zerlegen mit beachten
Code:
und dann kommt unten als erste "höchstwertige" Auswertung dieses rein
For i := 1 to Length(S) do
Case S[i] of ... '*', '/', '+', '-'[color=#ff0000], '(', ')'[/color]: Begin
Delphi-Quellcode:
For i := 0 to SL.Count - 3 do
If (SL[i] = '(') and TryStrToFloat(SL[i + 1], a) and (SL[i + 2] = ')') Then Begin SL.Delete(i + 2); SL.Delete(i); Goto Loop; End; [add] hab aber wirklich eine Vereinfachung gefunden :stupid:
Delphi-Quellcode:
dieses war ja einfach nur für "ist Operator", was doch auch soviel wie "ist keine Zahl" heißt :lol:
If ((i = 0) or AnsiMatchText(SL[i - 1], ['*', '/', '+', '-']))
also dieses sollte stattdessen auch gehn :stupid:
Delphi-Quellcode:
If ((i = 0) or not TryStrToFloat(SL[i - 1], b))
[add] hier noch mit Klammern und Div/Mod und ja natürlich kann man da vieles noch optimieren und zusammenfassen, aber das kann auch jeder selber machen |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Ich persönlich finde es ehrlich gesagt quatsch das ganze in einem String zu speichern um diesen dann wieder auseinander zu nehmen. Mein Taschenrechner aus der Schule hat damals alles direkt bei der Eingabe gerechnet. Dabei ist die Regelung auch recht einfach. Eine Zahl wirst erst zum bisherigen Ergebnis hinzugefügt (im Sinne der gewählten Rechenoperation) wenn die nächste Operation gewählt wurde.
Bei: 1+2*3 ist er also wie folgt vorgegangen (hat man im Display gesehen wann er das Zwischenergebnis angezeigt hat) Eingabe: 1 -> nichts passiert Eingabe: + -> 1 wird als Zwischenergebnis angezeigt Eingabe: 2 -> nichts passiert Eingabe: * -> 2 wird als Zwischenergebnis der Punktrechnung angezeigt Eingabe: 3 -> nichts passiert Eingabe: = -> Gesamt Ergebnis wird angezeigt Wenn man anstelle des "=" eine Strichoperation gewählt hätte würde er das Zwischenergebnis der Punktoperation zum vorherigen Zwischenergebnis dazu zählen und hätte das Gesamtzwischenergebnis angezeigt. Bei einer weiteren Punktoperation hingegen, wäre weiter auf das Zwischenergebnis der verändert wurden. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
So ähnlich hab ich das ja auch gemacht. Nur eben tu ich so, also ob der String schon da wäre. Also ich tu na nich so, denn der Strinque ist ja schon da. Ich prozessiere also Zeichen für Zeichen von links nach rechts, mach kein Look-Ahead und auch sonst keine Tricksereien.
Nur gefrickelt ist es halt. Soll eine Stackmaschine darstellen (ops = Operandenstack, numStack = Zahlen). Ich glaube, man sollte das nicht zu ernst nehmen. Es war ne 30min-Frickelei, weil ich mal schauen wollte, wie viel ich von diesem Mumpitz noch aus meiner Studienzeit wusste. Nichts, hat sich anschließend herausgestellt. Ich finde es aber eine hübsche Übung, denn es ist nicht trivial. Poste doch mal deinen Ansatz. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
Eine Schwierigkeit beim Parsen ist übrigens auch noch so etwas: +1++2*+3 Dies ist eine gültige Operation (überall einfach nur die Vorzeichen mit angegeben). So gut wie jeder Taschenrechner hat für das Vorzeichen eine extra Taste. Wenn man die Eingaben also sofort verarbeite, und nicht erst im nachhinein parst, hat man auch keine Probleme mit 2 aufeinanderfolgenden +, - oder sogar +- oder -+ da man dann bereits bei der Eingabe das Vorzeichen der Zahl zuordnet und sich somit die Zusatzarbeit für das korrekte Parsen spart. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Beim parsen eines ganzen Strings ist es dagegen auch recht einfach ... hab es schießlich auch hier in dem einfachen Code (siehe vorherige Beiträge) mit drinnen :angel: Noar, wenn du es unbedingt als Liveeingabe haben willst ... Hier wird übrigens die selbe Rechenfunktion genutzt, welche auch in Beitrag #28 drin ist, nur mit einem Unterschied:
Delphi-Quellcode:
Beim Zusammensetzen, werden eventuell noch nicht bearbeitete Zahlen "normalisiert" und es werden Leerzeichen eingefügt.
Finally
Result := ''; For i := 0 to SL.Count - 1 do Begin If TryStrToFloat(SL[i], a) Then SL[i] := FloatToStr(a); Result := Result + SL[i] + ' '; End; Result := Trim(Result); Ansonsten wird in dem Programm sozusagen einfach nur der eigegebene Befehl/Zeichen hinten an den Text drangehängt und alles gearst. Achtung, es sind auch Fehleingaben möglich, welche man aber auch praktisch ausnutzen kann (wie mir grad so in den Sinn kam), denn es werden ja alle möglichen Unterteile dennoch so weit wie möglich aufgelöst. z.B. kann man sowas eingeben "8 / / 8" ... dieses doppelte "//" wird natürlich nicht aufgelößt, so kann man jetzt etwas berechnen, macht dann einfach "//" , der alte Wert bleibt vorne erhalten und man kann hinten weiterrechnen. z.B. einfach mal dieses eingeben "3 + 5 / / 2 * 4 =" oder wie wäre es damit ... einfach mal über Strg+C in das Programm reinkopieren Zitat:
was mir grad noch auffiehl ist, daß beim letzen Beispiel das z.B. "8 + 88" vor "88 * 456" berechnet wird, da der String direkt im Edit verwaltet und dort schon aufgelöst wurde er rechnet praktisch so Zitat:
- entweder intern den die ganze Formel merken und nur das ausgerechnete anzeigen - oder (was wohl schöner zum Editieren ist) das "+" dort nicht auflösen, da die zugehörige "88" stärker an das "*" gebunden ist. PS: gibt es eigentlich ein "Standardevent" für Einfügen (Strg+C)? aktuell sieht es so aus
Delphi-Quellcode:
und bei mir funktioniert es, aber ich weiß nicht, ob es bei allen auch noch so geht.
Procedure TForm1.EditKeyPress(Sender: TObject; Var Key: Char);
If Key = #22 Then |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
Nee, im Ernst: Mit meiner Schleife geht das eins-fix-drei, denn man muss ja nur die beiden Stacks 'global', d.h. als private Felder in eine Klasse packen und dem Evaluator eine 'ProcessChar'-Methode spendieren, die ja nur aus dem Schleifenrumpf besteht. Et voilá: Fertig ist der Live-Rechn-o-mat. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
nja, ich hab das ja jetzt erstmal einfach als 'normales' Edit gelöst und da löscht Backspace (in der hochgeladenen Version das letzte Zeichen und alle neuen Zeichen werden hinten angehängt ... und ich meiner internen alktuellen Version wird dieses alles jeweils an der Cursorposition gemacht und dieses (also mitten drinnen was editieren) würde garnicht gehn, wenn man es direkt in den Stack schiebt.
|
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
Hab diesen Code in einen Testrechner eingebaut, der kennt aber
Delphi-Quellcode:
nicht... Also kennt er schon, ist aber nicht anwendbar...???
for c in term do
case c of '0'..'9': begin [edit=alzaimar] Mfg, alzaimar[/edit] |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
Delphi-Quellcode:
Aber Vorsicht! Der Code rechnet zwar mit Klammern aber trotzdem nicht richtig: '3*5+4*2/2' ergibt 11 statt 19!
for i:=1 to length(term) do begin
c := term[i]; case c of //... end; |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
erst die Vorzeichen +x und -x dann die Punktrechnungen *, /, DIV und MOD und erst zum Schluß + und - berechnen lassen sonst stimmt die Reihenfolge natürlich nicht. |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Zitat:
[edit] Verbesserter Code[/edit]
Delphi-Quellcode:
function Eval(Term: string): Integer;
function _Eval(term: string; var i: Integer): Integer; const isNone = 0; isNum = 1; isOp = 2; var numStack: array[0..10] of Integer; number, code, sign, sp, j: Integer; Ops: string; c: Char; function OpOrder(c: Char): Integer; begin if c = '$' then Result := -1 else Result := (Pos(c, '+-*/') + 1) div 2; end; begin fillchar(numstack, sizeof(numstack), 0); sign := 1; Ops := '$'; SP := 0; number := 0; Result := 0; code := isNone; while i < length(term) do begin inc(i); c := term[i]; case c of '0'..'9': begin number := 10 * number + ord(c) - 48; code := isNum; end; '(': begin number := _Eval(term, i); code := isNum; end; ' ': continue; '+', '-', '*', '/', ')': begin if code = isNum then begin numStack[SP] := sign * number; sign := 1; inc(SP); code := isNone; number := 0; end else if code = isOp then begin if c = '-' then sign := -sign; Continue end; code := isop; if Length(Ops) > 1 then begin while opOrder(c) <= OpOrder(Ops[Length(Ops)]) do begin dec(sp); case Ops[Length(Ops)] of '*': numstack[sp - 1] := numstack[sp - 1] * numstack[sp]; '/': numstack[sp - 1] := numstack[sp - 1] div numstack[sp]; '+': numstack[sp - 1] := numstack[sp - 1] + numstack[sp]; '-': numstack[sp - 1] := numstack[sp - 1] - numstack[sp]; end; numStack[sp] := 0; setLength(Ops, length(Ops) - 1); end; end; Ops := Ops + c; if c = ')' then begin number := NumStack[0]; break; end; end; end; end; result := Number; end; var i: Integer; begin i := 0; Result := _Eval('(' + term + ')', i); end; |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Ich habe jetzt versucht, in SL alles auszurechnen...
Sl enthält bspw. 1 + 2 * 3 Ich hab jetzt überlegt, ich wiederhole jetzt etwas, bis SL nur noch eine Zeile hat. Nur weiß ich nicht, wie ich das anstellen soll... Ich habs mit Repeat Until versucht:
Delphi-Quellcode:
begin
i:=0; repeat if SL[i]='*' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])*StrToFloat(SL[i+1]))); {Zahl vor und nach dem * werden multipliziert und in die Zeile der ersten Zahl geschrieben???} SL.Delete(SL.Count); {Jetzt soll die Zeile des Operators gelöscht werden} SL.Delete(SL.Count+1);{und die der zweiten Zahl} i:=i+1; {Geht zur Position des nächsten Rechenzeichens} exit; {Beendet, da wieder nach * gesucht werden soll->Neubeginn ab Repeat} end; if SL[i]='/' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])/StrToFloat(SL[i+1]))); SL.Delete(SL.Count); SL.Delete(SL.Count+1); i:=i+1; exit; end; if SL[i]='+' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])+StrToFloat(SL[i+1]))); SL.Delete(SL.Count); SL.Delete(SL.Count+1); i:=i+1; exit; end; if SL[i]='-' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])-StrToFloat(SL[i+1]))); SL.Delete(SL.Count); SL.Delete(SL.Count+1); i:=i+1; exit; end; until SL.Count = 1; Ich denke mal, das ist ziemlich falsch... Also den ersten Teil hab ich jetzt verstanden (StringList erstellen), aber jetzt weiß ich nicht weiter :( Bitte helft mir nochmal!!! Liebe Grüße! |
Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
Bei deiner Schleife würde i zuerst beim + vorbeikommen und dieses auflösen.
Jetzt aber einfach auf die Idee zu kommen die Schleife rückwärts laufen zu lassen wäre auch eine blöde Idee, (bevor zu also danfängst darüber nachzudenken) denn 1*2+3 würde dann wiederum falsch ausgewertet. du mußt einzelne/mehere Schleifen nacheinander machen ... und zwar für alle Stufen einzeln Vorzeichen (+-) - Punktoperationen (*/) - Strichoperationen (+-) ... genauso, wie man es auch auf'm Zettel selber machen würde - in der ersten Schleife nur die Vorzeichen (+ und -) also wenn "{keine Zahl, bzw. Operator} {+|-} {Zahl}" - dann die nächste Stufe die Punkte (* und : aka /) also wenn "{zahl} {*|/} {zahl}" - und nun die Striche (+ und -) also wenn "{zahl} {+|-} {zahl}" siehe Beitrag ![]() der Funktionsinterpreter vom Delphi-Treff kann das alles in nur einer Schleife machen, da er dort eine andere Verschachtelung der Zahlen und Operatoren genutzt wird. * + 1 2 3 da kann man immer alles gleich ausrechnen, welches "{operator} {zahl} {zahl}" entspricht und muß auf keine Reihenfolge achten, da die Reihenfolge durch die Verschachtelung vorgegeben wird also deinen Code erstmal in 2 Schleifen zerlegen
Delphi-Quellcode:
wenn am Ende mehr als ein Eintrag in SL vorliegt, dann stimmte etwas mit dem Term nicht, bzw. du hast etwas noch nicht umgewandelt (z.B. weil der Operator/Befehl noch nicht implementiert ist)
begin
i:=0; while i < SL.Count do begin if SL[i]='*' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])*StrToFloat(SL[i+1]))); {Zahl vor und nach dem * werden multipliziert und in die Zeile der ersten Zahl geschrieben???} SL.Delete(SL.Count); {Jetzt soll die Zeile des Operators gelöscht werden} SL.Delete(SL.Count);{und die der zweiten Zahl} {etwas wurde gefunden - fange von vorn an} i := 0; end else if SL[i]='/' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])/StrToFloat(SL[i+1]))); SL.Delete(SL.Count); SL.Delete(SL.Count); i := 0; end else i := i + 1; end; i:=0; while i < SL.Count do begin if SL[i]='+' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])+StrToFloat(SL[i+1]))); SL.Delete(SL.Count); SL.Delete(SL.Count); i := 0; end else if SL[i]='-' then begin SL[SL.Count-1]:=(FloatToStr(StrToFloat(SL[i-1])-StrToFloat(SL[i+1]))); SL.Delete(SL.Count); SL.Delete(SL.Count); i := 0; end else i := i + 1; end; hier z.B. "1 + 2 2 * 3" würde dein Code jetzt "3 6" ausgeben, da die letzen 2 Einträge nicht behandelt werden |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz