Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Problem mit Mathe-Parser (https://www.delphipraxis.net/142578-problem-mit-mathe-parser.html)

athomas 30. Okt 2009 15:52


Problem mit Mathe-Parser
 
Hallo zusammen,

ich sitz hier vor nem kleinen problem mit einem formelparser.
ich hab ne prozedur geschrieben, die einen klammerfreien ausdruck zerstückelt in zahlen und operatoren.
eine weitere prozedur soll dieses array in ne gleitkommazahl umwandeln. klappt soweit auch ganz gut, nur wenn ich ein negatives vorzeichen hab bekomm ich den fehler, dass der index das maximum meiner tstringlist überschreiten würde.
kann sich das bitte mal jemand ansehen :)

Delphi-Quellcode:
function arrBerechnen(s: TStringlist): real;
var
  i, j: integer;
  arr: TStringlist;
  ende: boolean;
begin
  arr:=TStringlist.create();
  arr.clear;
  arr:=s;

  //Produkt
  ende:=false;
  i:=1;
  if arr.count>1 then
    begin
      while not(ende) do
        begin
          if (arr[i]='*') then
            begin
              arr[i-1]:=floattostr(strtofloat(arr[i-1])*strtofloat(arr[i+1]));
              arr.delete(i);
              arr.delete(i);
            end;
          ende:=true;
          for j:=0 to arr.count-1 do
            if arr[j]='*' then
              ende:=false;    
          i:=i+1;
          i:=i mod (arr.count);
        end;
    end;
   
  //Quotient
  ende:=false;
  i:=1;
  if arr.count>1 then
    begin
      while not(ende) do
        begin
          if (arr[i]='/') then
            begin
              arr[i-1]:=floattostr(strtofloat(arr[i-1])/strtofloat(arr[i+1]));
              arr.delete(i);
              arr.delete(i);
            end;
          ende:=true;
          for j:=0 to arr.count-1 do
            if arr[j]='/' then
              ende:=false;    
          i:=i+1;
          i:=i mod (arr.count);
        end;
    end;
       
  //Differenz
  ende:=false;
  i:=1;
  if arr.count>1 then
    begin
      while not(ende) do
        begin
          if (arr[i]='-') then
            begin
              if i=1 then
                begin
                  arr[i-1]:=floattostr(- strtofloat(arr[i]));
                  arr.delete(i);
                end
              else
                begin
                  arr[i-1]:=floattostr(strtofloat(arr[i-1])-strtofloat(arr[i+1]));
                  arr.delete(i);
                  arr.delete(i);
                end;
            end;
          ende:=true;
          for j:=0 to arr.count-1 do
            if (arr[j]='-')and(length(arr[j])=1) then
              ende:=false;
          i:=i+1;
          i:=i mod (arr.count);
        end;
    end;
  //Summe
  ende:=false;
  i:=1;
  if arr.count>1 then
    begin
      while not(ende) do
        begin
          if (arr[i]='+') then
            begin
              arr[i-1]:=floattostr(strtofloat(arr[i-1])+strtofloat(arr[i+1]));
              arr.delete(i);
              arr.delete(i);
            end;
          ende:=true;
          for j:=0 to arr.count-1 do
            if arr[j]='+' then
              ende:=false;
          i:=i+1;
          i:=i mod (arr.count);
        end;
    end;
 
  result:=strtofloat(arr[0]);
  arr.free;
end;

himitsu 30. Okt 2009 16:10

Re: Problem mit Mathe-Parser
 
Zitat:

Delphi-Quellcode:
arr:=s;

hier überschreibst du die vorher etstelle Instant der Stringliste!
richtiger wäre:
Delphi-Quellcode:
arr.Assign(s);
PS: TStrings als Parameter macht sich besser (so kann man auch StringList-ähnliche Dinge übergeben
(z.B. Memo1.Lines , welches ich für meinen Test mal schnell genommen hab)


Zitat:

Delphi-Quellcode:
if i=1 then

das Minus ist ja wohl im Index 0 :zwinker:
Zitat:

Delphi-Quellcode:
for j:=0 to arr.count-1 do
...
i:=i mod (arr.count);

setzt i auf 0 und führt die While-Schleite nochmals ab 0 aus
PS: fange gleich mit i:=0; an (bei + und -), dann muß da nicht doppelt bearbeitet werden


PS: das + gibt es auch als Vorzeichen (hast du ganz vergessen)
PSS: + und - als Vorzeichen innerhalb eines Strings "1+-2" dürfte auch Probleme bereiten

athomas 30. Okt 2009 16:32

Re: Problem mit Mathe-Parser
 
danke schonmal für die schnelle antwort

ich hab deine tipps befolgt und die while-schleife von null gestartet:
Delphi-Quellcode:
//Differenz
  ende:=false;
  i:=0;
  if arr.count>1 then
    begin
      while not(ende) do
        begin
          if (arr[i]='-') then
            begin
              if i=0 then
                begin
                  arr[i]:=floattostr(- strtofloat(arr[i+1]));
                  arr.delete(i+1);
                end
              else
                begin
                  arr[i-1]:=floattostr(strtofloat(arr[i-1])-strtofloat(arr[i+1]));
                  arr.delete(i);
                  arr.delete(i);
                end;
            end;
          ende:=true;
          for j:=0 to arr.count-1 do
            if (arr[j]='-')and(length(arr[j])=1) then
              ende:=false;
          i:=i+1;
          i:=i mod (arr.count);
        end;
    end;
negative vorzeichen funktionieren jetzt soweit ganz gut, aber wenn ich z.b. -1-2-3-4-5 eingebe, konnt -7 raus ^^
was stimmt denn noch nicht

himitsu 30. Okt 2009 16:42

Re: Problem mit Mathe-Parser
 
nimm mal arr.Text in die Liste der überwachten Ausdrücke (Strg+Alt+W) auf,
setze einen Haltepunkt (F5) vor diese Schleife und geh dann ab dort die Schleife mal im Einzelschritt (F7) durch

in der Liste kannst du dann schrittweise beobachten, was mit deinem arr passiert


PS: wenn arr.Text zu unübersichtlich ist, dann kann man auch dieses in diese Liste aufnehmen
(Funktionsaufrufe natürlich gestatten)
Code:
StringReplace(arr.Text, sLineBreak, ' | ', [rfReplaceAll])
und wenn es heißt "Funktion wurde vom Compiler entfernt", dann noch irgendwo im QuellText diese Funktion verwenden
z.B. einfach irgendwo StringReplace('','','',[]); einfügen (zwar voll sinnlos, aber nun ist diese Funktion vorhanden :stupid: )

[add]
mach aus diesem
Delphi-Quellcode:
i:=i+1;
i:=i mod (arr.count);
einfach nur
Delphi-Quellcode:
i:=0;
der Grund ist, daß so die Werte in der falschen Reihenfolge aufgelöst werden
-1-2-3-4-5 und dein Code macht ((-1)-2)-(3-4)-5

athomas 30. Okt 2009 17:17

Re: Problem mit Mathe-Parser
 
wenn ich doch aber
Delphi-Quellcode:
i:=i+1;
i:=i mod (arr.count);
mit i:=0 ersetze komm ich in ne endlos-schleife, oder hab ich dich falsch verstanden?

ach ja, das problem mit -- oder +- hab ich einfach mit stringreplace lösen können :)

aber was mir noch aufgefallen ist: x*(-4) oder x/(-4) funktioniert auch nicht

Namenloser 30. Okt 2009 17:31

Re: Problem mit Mathe-Parser
 
Zitat:

Zitat von athomas
ach ja, das problem mit -- oder +- hab ich einfach mit stringreplace lösen können :)

Was gar nicht nötig wäre, weil das kein korrekter mathematischer Ausdruck ist. :wink:

himitsu 30. Okt 2009 17:33

Re: Problem mit Mathe-Parser
 
theoretisch nicht,

aber nachdem
> - 1 - 2 - 3 - 4 - 5
bis hier aufgelöst wurde
> -3 - 3 - 4 - 5
hier nach ist i nun 1
und es wird grad noch das - getroffen
> -6 - 4 - 5
danach steht i durch deine Berechnung aber auf 2,
verfehlt knapp das 1. "-" und nimmt sich als Nächstes erstmal das 2. "-" vor, also 4 - 5
> -6 - -1
und im letzten Durchgang kommt es dann natürlich zu
> -7

stimmt ... die Endlosschleife hab ich glatt übersehn
versuch mal nur i:=i+1; an dieser Stelle und wenn du was ersetzt hast, dann ma da gleich ein i:=i-1; oder i:=-1; rein :gruebel:

Zitat:

Zitat von athomas
ach ja, das problem mit -- oder +- hab ich einfach mit stringreplace lösen können :)

man hätte auch statt i=0 auf "ist davor nichts oder noch ein anderer Operator (+-*/)" bzw. "ist davor KEINE Zahl" prüfen können.
denn wenn dieses zutrifft, dann handelt es sich bei diesem + oder - um ein Vorzeichen ... ansonsten um einen Operator

@NamenLozer:
1--2 aka 1 - -2 ist also nicht korrekt?

athomas 30. Okt 2009 17:42

Re: Problem mit Mathe-Parser
 
stimmt ja, hab ich wohl übersehen: wenn ich die funktion delete aufrufe verschiebt sich ja das ganze array

also das addieren und subtrahieren funktioniert jetzt, aber ich hab jetzt ein problem beim multiplizieren mit negativen zahlen:

Delphi-Quellcode:
//Produkt
  ende:=false;
  i:=1;
  if arr.count>1 then
    begin
      while not(ende) do
        begin
          if (arr[i]='*') then
            begin
              arr[i-1]:=floattostr(strtofloat(arr[i-1])*strtofloat(arr[i+1]));
              arr.delete(i);
              arr.delete(i);
              i:=i-2;
            end;
          ende:=true;
          for j:=0 to arr.count-1 do
            if arr[j]='*' then
              begin
                ende:=false;
                break;
              end;
          i:=i+1;
        end;
    end;
wenn ich -2 * -2 rechne gibt er mir -2 aus, als ob er -* als einen unbekannten operator ansehen würde

Namenloser 30. Okt 2009 17:46

Re: Problem mit Mathe-Parser
 
Zitat:

Zitat von himitsu
@NamenLozer:
1--2 aka 1 - -2 ist also nicht korrekt?

Ja. Bei so etwas sind Klammern nötig: Nur 1-(-2) ist formal korrekt.

athomas 30. Okt 2009 17:54

Re: Problem mit Mathe-Parser
 
war auch mein erster gedanke:
(-2)*(-2) kommt aber auch -2 raus

himitsu 30. Okt 2009 17:59

Re: Problem mit Mathe-Parser
 
@NamenLozer: so schreibt aber kein Mensch und da Vorzeichen die höchste Priorität haben, ist praktisch auch keine Klammer nötig

Zitat:

Zitat von athomas
aber ich hab jetzt ein problem beim multiplizieren mit negativen zahlen:

Das Problem ist hierbei, daß du in dieser Reihenfolge auswertest
1. *
2. /
3. -
4. +

aber eigentlich ist die korrekte Reihenfolge so
1. Vorzeichen +-
2. Punktrechnung */
3. Strichrechnung +-

oder auch nacheinander
1a. Vorzeichen +
1b. Vorzeichen -
2a. Punktrechnung *
2b. Punktrechnung /
3a. Strichrechnung +
3b. Strichrechnung -
(a und b kann auch vertauscht werden)

schau mal dort
http://www.delphipraxis.net/internal...ghlight=parser
das Problem ist auch, daß du ungeprüft einfach alles miteinander verrechnest
also bei 1--2 wird 1 - "-" gerechnet

die Vorzeichenberechnungen müßtest du also noch vor die Berechnungen von * und / verlegen
und dann z.B. nur bei folgender Bedingung diese Berechnungen ausführen
((i = 0) or istKeineZahl(sl[i-1])) and (sl[i] = '-') and istZahl(sl[i+1])

athomas 30. Okt 2009 18:30

Re: Problem mit Mathe-Parser
 
also ich hab das mit den vorzeichen noch ergänzt, es will aber immernochnicht klappen:
Delphi-Quellcode:
//Vorzeichen
  ende:=false;
  i:=0;
  if arr.count>1 then
    begin
      while not(ende) do
        begin
          if ( (i = 0)or(not(isReal(arr[i-1]))) )and(arr[i]='-')and(isReal(arr[i+1])) then
            begin
              arr[i]:=floattostr(-strtofloat(arr[i+1]));
              arr.delete(i+1);
              i:=i-1;
            end;
          i:=i+1;
          if i>=arr.count-1 then
            ende:=true;
        end;
    end;

athomas 31. Okt 2009 10:24

Re: Problem mit Mathe-Parser
 
hab den fehler entdeckt: die funktion isReal hat negative werte nicht als reale werte angesehen

also vielen dank für die tolle hilfe. hat mich echt weitergebracht :)

himitsu 31. Okt 2009 10:37

Re: Problem mit Mathe-Parser
 
gern geschehen und viel Spaß noch, mit deinem Parser :)

himitsu 10. Nov 2009 08:07

Re: Problem mit Mathe-Parser
 
[nicht wichtig]

mathe parser

(man mag es nicht glauben, aber das Zusammengesetzte findet die Suchfunktion nicht, wenn es auseinander ist)

sind nur'n paar Stichworte für die Suchfunktion

Namenloser 10. Nov 2009 13:27

Re: Problem mit Mathe-Parser
 
Zitat:

Zitat von himitsu
@NamenLozer: so schreibt aber kein Mensch und da Vorzeichen die höchste Priorität haben, ist praktisch auch keine Klammer nötig

Wenn du in der Schule die Klammern weglässt, zählt das als Fehler. (Sorry, hab den Post jetzt erst gesehn)

himitsu 10. Nov 2009 13:52

Re: Problem mit Mathe-Parser
 
Zitat:

Zitat von NamenLozer
Wenn du in der Schule die Klammern weglässt, zählt das als Fehler.

OK, ist jetzt schon ein/zwei Jährchen her, aber ich kann mich garnicht an sowas erinnern.
Oder haben wir in der DDR noch anders gerechnet? :gruebel:


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:20 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