Delphi-PRAXiS
Seite 5 von 5   « Erste     345   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Term (Zeichenfolge 1+2*3) in Fließkommazahl (https://www.delphipraxis.net/140346-term-zeichenfolge-1-2%2A3-fliesskommazahl.html)

Delphi-Narr 23. Okt 2009 14:39

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
 
Delphi-Quellcode:
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;
          begin
               begin
               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+1);{und die der zweiten Zahl} 
                               {etwas wurde gefunden - fange von vorn an} 
                               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+1);
                               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+1);{und die der zweiten Zahl} 
                               {etwas wurde gefunden - fange von vorn an} 
                               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+1);
                               i := -1;
                         end
                      else
                         i := i + 1;
                  end;

                   
          end;
          end;
      Finally
           
        Result := '';
        For i := 0 to SL.Count - 1 do Result := Result + SL[i];
       
      End;
    Finally
      SL.Free;
    End;
  End;
Hab das jetzt da stehen. Die erste Schleife kommt später noch, wird ja bei 1+2*3 nicht benötigt.
Ich klick auf = und krieg die Meldung: Der Index der Liste überschreitet das Maximum (2).
Vorher hatte ich immer die Meldung: Der Index der Liste überschreitet das Maximum(Anzahl der Zeilen der Stringlist)...

himitsu 23. Okt 2009 14:55

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
 
für sowas gibt es den Debuger ... da schaut man wo es knallt und auch gleich warum :zwinker:

da fällt dann auf, daß es hier knallt
Delphi-Quellcode:
SL.Delete(i);
SL.Delete(i+1); <<<
die aktuellen Werte sind da
Code:
i = 3

0: 1
1: +
2: 2
3: *
4: 3
Code:
0: 1
1: +
2: 6  << durch SL[i-1]:=...; geändert
      << der alte Wert an Index 3 wurde durch SL.Delete(i); gelöscht
3: 3  << hat jetzt den Index 3 und nicht mehr 4
ja und nun versuchts du SL.Delete(i + 1);
i+1 = 4 und die 4 gibt es nicht mehr ... also da auch nur SL.Delete(i);


PS: das i := -1; ist jetzt falsch, da war, bevor ich dort mal das ELSE einfügt,
denn vorher wurde nach der Schleife das i:=i+1; noch mit ausgeführt und -1+1=0 ... also der Anfang, aber wegen des Else muß da jetzt auch stattdessen i:=0; hin (hab es oben mal editiert)

Delphi-Narr 23. Okt 2009 15:22

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
 
Mit i:=i-1 geht's auch...
Danke für die Hilfe!

Hawkeye219 23. Okt 2009 16:09

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
 
Hallo,

man könnte das Problem auch mit einigen geschachtelten Routinen lösen:

Delphi-Quellcode:
function Eval (s: string): Integer;

  function EatChar (const aSet: TSysCharSet; var ch: Char): Boolean;
  begin
    Result := ((s <> '') and (s[1] in aSet));
    if Result then
      begin
        ch := s[1];
        s := TrimLeft(Copy(s, 2, MaxInt));
      end;
  end;

  function Term: Integer;

    function Summand: Integer;

      function Factor: Integer;
      var
        ErrPos: Integer;
        op: Char;
      begin
        if EatChar(['+', '-', '('], op) then
          case op of
            '+': Result := Factor;
            '-': Result := -Factor;
            '(': begin
                   Result := Term;
                   if (not EatChar([')'], op)) then
                     raise Exception.Create('missing ")"');
                 end;
          else
            Result := 0; // calm compiler
          end
        else
          begin
            Val (s, Result, ErrPos);
            if (ErrPos = 0) then
              s := ''
            else
              s := TrimLeft(Copy(s, ErrPos, MaxInt));
          end;
      end;

    var
      op: Char;
    begin
      Result := Factor;
      while EatChar(['*', '/'], op) do
        case op of
          '*': Result := Result * Factor;
          '/': Result := Result div Factor;
        end;
    end;

  var
    op: Char;
  begin
    Result := Summand;
    while EatChar(['+', '-'], op) do
      case op of
        '+': Result := Result + Summand;
        '-': Result := Result - Summand;
      end;
  end;

begin
  s := Trim(s);
  Result := Term;
  if (s <> '') then
    raise Exception.Create('unknown operation');
end;
In der jetzigen Form verarbeitet der Parser nur Integer-Ausdrücke, die Fehlerbehandlung verdient ihren Namen eigentlich nicht. Aber es soll ja lediglich das Prinzip verdeutlicht werden.

Gruß Hawkeye

himitsu 10. Nov 2009 08:04

Re: Term (Zeichenfolge 1+2*3) in Fließkommazahl
 
[nicht wichtig]

mathe parser

sind nur'n paar Stichworte für die Suchfunktion


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:59 Uhr.
Seite 5 von 5   « Erste     345   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz