Thema: Delphi Parser Kommarechnung

Einzelnen Beitrag anzeigen

Benutzerbild von Delphi-Narr
Delphi-Narr

Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
 
Delphi 2007 Professional
 
#10

AW: Parser Kommarechnung

  Alt 5. Sep 2010, 10: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 10:44 Uhr)
  Mit Zitat antworten Zitat