![]() |
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 05:22 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-2025 by Thomas Breitkreuz