Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
Delphi 2007 Professional
|
AW: Parser Kommarechnung
5. Sep 2010, 11:35
Ich habe das auch gemacht (also decimal:=0), klappt aber nicht richtig (rechnet falsch)...
Bei 1,1 * 9 kommt nicht 9,9 raus sondern 0,4 oder so etwas...
Ich habe mal einen komplett neuen geschrieben, der klappt jetzt auch...
Der schreibt den Term nach Zahlen und Operatoren sortiert in eine Liste, fügt oder löscht falsche Rechenzeichen (hinzu), geht dann den Term von HINTEN durch und sucht nach Klammern, löst diese auf. Dann normal nach Potemzen suchen und auflösen und dann Punkt vor Strich.
Ich hätte mir zwar das normale auflösen (nach den Klammern) sparen können, indem ich einfach Klammern aufrufe, aber aus Testzwecken habe ich das stehen lassen (um die Zehnmilliarden Fehler beim durchgehen zu umgehen).
Hier mein Ergebnis:
Delphi-Quellcode:
function TermTOFloat(Term: string):real;
function Klammern(T: string): string;
Var SL: TStringList;
i: Integer;
S: string;
Begin
{Falls das erste Zeichen ein Rechenzeichen wie + oder - ist, so wird eine Null eingefügt,
um die Rechnung fortzusetzen (Beim Rechnen würde sonst ein Fehler auftreten)}
S:=T;
case S[1] of
' +',' -':
begin
insert(' 0',S,1);
end;
{Die Rechenzeichen * und / werden gelöscht}
' *',' /':
begin
Delete(S,1,1);
end;
end;
//Rechenzeichen am Ende werden gelöscht
case S[Length(S)] of
' +',' -',' *',' /':
begin
Delete(S,Length(S),1);
end;
end;
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;
{Ab hier wird gerechnet}
begin
begin
i:=0;
while i < SL.Count do
begin
if SL[i]=' ^' then
begin
SL[i-1]:=(FloatToStr(Power(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(i);
{Jetzt soll die Zeile des Operators gelöscht werden}
SL.Delete(i); {und die der zweiten Zahl}
{etwas wurde gefunden - fange von vorn an}
i := i-1;
end
else
i := i + 1;
end;
i:=0;
while i < SL.Count do
begin
if SL[i]=' *' then
begin
SL[i-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(i);
{Jetzt soll die Zeile des Operators gelöscht werden}
SL.Delete(i); {und die der zweiten Zahl}
{etwas wurde gefunden - fange von vorn an}
i := i-1;
end
else
if SL[i]=' /' then
begin
SL[i-1]:=(FloatToStr(StrToFloat(SL[i-1])/StrToFloat(SL[i+1])));
SL.Delete(i);
SL.Delete(i);
i := i-1;
end
else
i := i + 1;
end;
i:=0;
while i < SL.Count do
begin
if SL[i]=' +' then
begin
SL[i-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(i);
{Jetzt soll die Zeile des Operators gelöscht werden}
SL.Delete(i); {und die der zweiten Zahl}
{etwas wurde gefunden - fange von vorn an}
i := i-1;
end
else
if SL[i]=' -' then
begin
SL[i-1]:=(FloatToStr(StrToFloat(SL[i-1])-StrToFloat(SL[i+1])));
SL.Delete(i);
SL.Delete(i);
i := i-1;
end
else
i := i + 1;
end;
end;
end;
Finally
Result := SL[0];
end;
Finally
SL.Free;
End;
end;
Var SL: TStringList;
i,p,j,a: Integer;
S,tmp: string;
Begin
Result:=0;
{Falls das erste Zeichen ein Rechenzeichen wie + oder - ist, so wird eine Null eingefügt,
um die Rechnung fortzusetzen (Beim Rechnen würde sonst ein Fehler auftreten)}
S:=Term;
case S[1] of
' +',' -':
begin
insert(' 0',S,1);
end;
{Die Rechenzeichen * und / werden gelöscht}
' *',' /':
begin
Delete(S,1,1);
end;
end;
//Rechenzeichen am Ende werden gelöscht
case S[Length(S)] of
' +',' -',' *',' /':
begin
Delete(S,Length(S),1);
end;
end;
//Klammern durchsuchen und prüfen, ob ein Rechenzeichen davor steht, sonst * einfügen
for i:=2 to Length(S) do
begin
if (S[i]=' (') and (pos(S[i-1],' +-*/')=0) then insert(' *',S,i);
end;
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;
//Klammern suchen und auflösen
i:=SL.count-1;
while i>=0 do
begin
if SL[i]=' (' then
begin
p:=i;
tmp:=' ';
j:=p+1;
while (SL[j]<>' )') do
begin
tmp:=tmp+SL[j];
j:=j+1;
if j=SL.count then break;
end;
if j=SL.count then j:=j-1;
tmp:=Klammern(tmp);
SL[p]:=tmp;
//Löschen
a:=p+1;
for p:=P+1 to j do
begin
SL.Delete(a);
end;
end;
i:=i-1;
end;
tmp:=' ';
for i:=0 to SL.count-1 do
tmp:=tmp+SL[i];
{Ab hier wird gerechnet}
begin
begin
i:=0;
while i < SL.Count do
begin
if SL[i]=' ^' then
begin
SL[i-1]:=(FloatToStr(Power(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(i);
{Jetzt soll die Zeile des Operators gelöscht werden}
SL.Delete(i); {und die der zweiten Zahl}
{etwas wurde gefunden - fange von vorn an}
i := i-1;
end
else
i := i + 1;
end;
i:=0;
while i < SL.Count do
begin
if SL[i]=' *' then
begin
SL[i-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(i);
{Jetzt soll die Zeile des Operators gelöscht werden}
SL.Delete(i); {und die der zweiten Zahl}
{etwas wurde gefunden - fange von vorn an}
i := i-1;
end
else
if SL[i]=' /' then
begin
SL[i-1]:=(FloatToStr(StrToFloat(SL[i-1])/StrToFloat(SL[i+1])));
SL.Delete(i);
SL.Delete(i);
i := i-1;
end
else
i := i + 1;
end;
i:=0;
while i < SL.Count do
begin
if SL[i]=' +' then
begin
SL[i-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(i);
{Jetzt soll die Zeile des Operators gelöscht werden}
SL.Delete(i); {und die der zweiten Zahl}
{etwas wurde gefunden - fange von vorn an}
i := i-1;
end
else
if SL[i]=' -' then
begin
SL[i-1]:=(FloatToStr(StrToFloat(SL[i-1])-StrToFloat(SL[i+1])));
SL.Delete(i);
SL.Delete(i);
i := i-1;
end
else
i := i + 1;
end;
end;
end;
Finally
tmp:=SL[0];
Try
Result := StrToFloat(SL[0]);
except
Result:=0;
end;
end;
Finally
SL.Free;
End;
end;
Viele Grüße und viel Spaß damit
Geändert von Delphi-Narr ( 5. Sep 2010 um 11:44 Uhr)
|