| 
| Autor | Beitrag |  
| Sven 
          Beiträge: 314
 
 
 D6 Ent, K3 Pro (patched)
 
 | 
Verfasst: Mo 08.12.03 13:10 
 
Hier noch ein Parser von Mathematischen Funktionen:
 Es kann z.B. folgender String verarbeitet werden:
2.34*(3.45+123)-Trunc(Cos(Rad(45)))/47 			Und hier eine kurze Enführung:									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 38:
 39:
 40:
 41:
 42:
 43:
 44:
 45:
 46:
 47:
 48:
 49:
 50:
 51:
 52:
 53:
 54:
 55:
 56:
 57:
 58:
 59:
 60:
 61:
 62:
 63:
 64:
 65:
 66:
 67:
 68:
 69:
 70:
 71:
 72:
 73:
 74:
 75:
 76:
 77:
 78:
 79:
 80:
 81:
 82:
 83:
 84:
 85:
 86:
 87:
 88:
 89:
 90:
 91:
 92:
 93:
 94:
 95:
 96:
 97:
 98:
 99:
 100:
 101:
 102:
 103:
 104:
 105:
 106:
 107:
 108:
 109:
 110:
 111:
 112:
 113:
 114:
 115:
 116:
 117:
 118:
 119:
 120:
 121:
 122:
 123:
 124:
 125:
 126:
 127:
 128:
 129:
 130:
 131:
 132:
 133:
 134:
 135:
 136:
 137:
 138:
 139:
 140:
 141:
 142:
 143:
 144:
 145:
 146:
 147:
 148:
 149:
 150:
 151:
 152:
 153:
 154:
 155:
 156:
 157:
 158:
 159:
 160:
 161:
 162:
 163:
 164:
 165:
 166:
 167:
 168:
 169:
 170:
 171:
 172:
 173:
 174:
 175:
 176:
 177:
 178:
 179:
 180:
 181:
 182:
 183:
 184:
 185:
 186:
 187:
 188:
 
 | unit modParser;
 interface
 uses sysutils,stdctrls,classes,math,dialogs;
 
 TYPE
 EparserError=class(Exception);
 Rparameters= record x,y,z:extended; end;
 Const parameter:Rparameters=(x:1;y:1;z:1);
 TYPE
 
 TZMathEdit=class(TEdit)
 private
 function getEvaluatedString:string;
 public
 property TextValue:string read getEvaluatedString;
 end;
 
 function EvaluateToFloat(s0:string):extended;
 Function GetEvaluationError:string;
 procedure Register;
 
 implementation
 
 const  sopps:string=('+-*/^');
 Pi          = 3.1415926535897932384626433832795;
 var EvaluationError:string;
 
 
 procedure Register;
 begin
 RegisterComponents('Samples', [TZMathEdit]);
 end;
 function evaluate(s0:string):extended;forward;
 
 procedure matchbracket(var i:integer;s0:string);
 var j,len:integer;
 begin
 j:=1;len:=length(s0);
 repeat inc(i);
 if i>len then raise EparserError.Create('missing '')''');
 if s0[i]='(' then inc(j);
 if s0[i]=')' then dec(j);
 if j<0 then raise EparserError.Create('missing ''(''');
 until j=0;
 end;
 
 function getvalue(s0:string):extended;
 begin
 if length(s0)<1 then raise EparserError.Create('syntax error');
 if length(s0)=1 then result:=StrToDbl(s0) else
 case s0[1] of
 'x':result:=parameter.x;
 'y':result:=parameter.y;
 'z':result:=parameter.z;
 else result:=StrToDbl(s0);
 end;
 end;
 
 function specialF(p1:integer;s0:string):extended;
 var operstr: string;
 arg    : extended;
 begin
 operstr:=copy(s0,1,p1-1);
 operstr := LowerCase(operstr);
 if s0[length(s0)]<>')' then EparserError.CreateFmt('incorrect syntax %s',[s0]);
 arg:=evaluate(copy(s0,p1+1,length(s0)-p1-1));
 if operstr = 'sin'    then result:=sin(arg)
 else if operstr = 'cos'    then result:=cos(arg)
 else if operstr = 'tan'    then result:=sin(arg)/cos(arg)
 else if operstr = 'cot'    then result:=cos(arg)/sin(arg)
 else if operstr = 'sec'    then result:=1/sin(arg)
 else if operstr = 'cosec'  then result:=1/cos(arg)
 else if operstr = 'arctan' then result:=arctan(arg)
 else if operstr = 'arccot' then result:=1/arctan(arg)
 else if operstr = 'arcsin' then result:=arcsin(arg)
 else if operstr = 'arccos' then result:=arccos(arg)
 else if operstr = 'log'    then result:=ln(arg)/ln(10)
 else if operstr = 'ln'     then result:=ln(arg)
 else if operstr = 'exp'    then result:=exp(arg)
 else if operstr = 'sqrt'   then result:=sqrt(arg)
 else if operstr = 'rad'    then result:=arg*Pi/180
 else if operstr = 'deg'    then result:=arg*180/Pi
 else if operstr = 'pi'     then result:=Pi
 else if operstr = 'round'  then result:=Round(arg)
 else if operstr = 'trunc'  then result:=Trunc(arg)
 
 else raise EparserError.CreateFmt('unknown function %s',[s0]);
 end;
 
 function calculate(p1:integer;s0:string):extended;
 var v1,v2:extended;
 begin
 v1:=evaluate(copy(s0,1,p1-1));
 v2:=evaluate(copy(s0,p1+1,length(s0)-p1));
 case s0[p1] of
 '+': result:=v1+v2;
 '-': result:=v1-v2;
 '/': result:=v1/v2;
 '*': result:=v1*v2;
 '^': result:=exp(v2*ln(v1));
 else raise EparserError.CreateFmt('invalid operation %s',[s0]);
 end;
 end;
 
 function getfirstopp(tot:integer;s0:string):integer;
 var i:integer;
 begin
 if tot=0 then tot:=length(s0);
 for i:=1 to 5 do begin
 result:=pos(sopps[i],s0);
 if ((i<3) and (result>0)) then
 if ((result=1) or (pos(s0[result-1],sopps)>0)) then result:=0;
 if result>0 then if result<tot then exit;
 end;
 if result>tot then result:=0;
 end;
 
 function Evaluate(s0:string):extended;
 var p1,p2,q1:integer;
 begin
 p1:=pos('(',s0);p2:=p1;
 if p2>0 then matchbracket(p2,s0);
 if p1=1 then begin
 if p2=length(s0) then begin
 delete(s0,p2,1);delete(s0,1,1);
 result:=evaluate(s0);
 end
 else result:=calculate(p2+1,s0);
 exit;
 end;
 q1:=getfirstopp(p1,s0);
 if (p1+q1=0) then begin
 result:=getvalue(s0);
 exit;
 end;
 if q1<>0 then result:=calculate(q1,s0)
 else if length(s0)>p2 then result:=calculate(p2+1,s0)
 else result:=specialF(p1,s0);
 end;
 
 procedure Cleanup(var s0:string);
 var i:integer;
 begin
 s0:=lowercase(s0);
 i:=pos(' ',s0);
 while i>0 do begin
 delete(s0,i,1);
 i:=pos(' ',s0);
 end;
 end;
 
 function TZMathEdit.GetEvaluatedString:string;
 var s0:string;
 begin
 s0:=text;
 TRY
 cleanup(s0);
 result:=FloatToStr(Evaluate(s0));
 EXCEPT
 on e:exception do result:=e.message;
 END;
 end;
 
 function EvaluateToFloat(s0:string):extended;
 begin
 TRY
 evaluationerror:='';
 Cleanup(s0);
 result:=Evaluate(s0);
 EXCEPT
 on e:exception do begin
 evaluationerror:=e.message;
 result:=0;
 end;
 END;
 end;
 
 Function GetEvaluationError:string;
 begin
 result:=evaluationerror;
 end;
 
 end.
 |  TZMathedit Komponente: Installiert modParser.pas wie gehabt. Es erscheint auf der Palettenseite "Samples".
 Die Benutzung erfolgt genau wie die von TEdit, es gibt jedoch eine zusätzliche Eigenschaft:
TextValue:string;  enthält das Ergebnis des Ausdruckes in Text, oder eine fehlermeldung.
 Beispiel: 
    Setze TZMathEdit auf einer Form ab, dazu ein TLabel. In dessen OnChange Ereignisbehandlungsroutine schreibe folgendes:
  Label1.Caption:=ZMathEdit1.TextValue; Alternativ kann man auch auf die Einbindung der Komponente auf einer Form verzichten und die funktion EvaluateToFloat(s0:string):extended;  direkt verwenden. Diese Funktion sollte nur zusammen mit GetEvaluationError:string;  verwendet werden, ist aber nicht unbedingt erforderlich
 Beispiel:
    value:=EvaluateToFloat('sqrt(0.5*exp(x)-0.5*sin(y))');
    if GetEvaluationError<>'' then label1.caption:=GetEvaluationError;
 Es können auch die Variablen x, y und z verwendet werden
 Beispiel:
   x:= ...     etc._________________MDK 9.1, Kernel 2.4.21, KDE 3.1 Kylix 3 Pro (patched), nutze aber auch Windows 
 Zuletzt bearbeitet von Sven am Mo 08.12.03 15:47, insgesamt 4-mal bearbeitet
 |  |  |  
| Popov 
          Beiträge: 1655
 Erhaltene Danke: 13
 
 WinXP Prof.
 Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
 
 | 
Verfasst: Mo 08.12.03 13:29 
 
Auch an dich: wie wäre es mit einem Beispiel, welche Funktion muß man benutzen, welche Mat-Funktionen beherscht deine Unit?
 Leute, wenn ihr zu faul seit etwas dazuzuschreiben, dann last das Posten. Was soll man mit Units von denen man nicht weißt wie sie funktionieren. Ein wenig Hilfe-Beschreibung wäre nicht schlecht. Wenn Ihr nicht wißt wie das geht, dann guckt euch die Delphihilfe an.
 _________________ Popov
 |  |  |  
| Sven  
          Beiträge: 314
 
 
 D6 Ent, K3 Pro (patched)
 
 | 
Verfasst: Mo 08.12.03 14:03 
 
So umfangreich ist die Klasse nicht, als das man eine Anleitung dafür bräuchte, oder?
 Ansonsten probiers mal mit:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 
 | string := 2.34*(3.45+123)-Trunc(Cos(Rad(45)))/47; 
 Ergebnis := EvaluateToFloat(string);
 |  Es besteht übrigens die Möglichkeit die Unit einzubinden und wie oben gezeigt zu verwenden, oder als Komponente, wie man halt eine Komponente verwendet.
 Übrigens Popov: Wer lesen kann ist klar im Vorteil, also setzen ... sechs._________________MDK 9.1, Kernel 2.4.21, KDE 3.1 Kylix 3 Pro (patched), nutze aber auch Windows |  |  |  
| Popov 
          Beiträge: 1655
 Erhaltene Danke: 13
 
 WinXP Prof.
 Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
 
 | 
Verfasst: Mo 08.12.03 14:32 
 
	  | Sven hat folgendes geschrieben: |  	  | Übrigens Popov: Wer lesen kann ist klar im Vorteil, also setzen ... sechs. | 
 Diesen Spruch kann man loslassen wenn du irgendwo eine Beschreibung gemacht hättest, ich sie aber übersehen hätte. War aber nicht so. Du gehst einfach davon aus, weil du deine Unit gut kennst, daß sie selbsterklärend ist. Woher nimmst du aber die unverfrorenheit anzunehmen, daß jeder der deine Unit benutzen will, sie zuerst studieren muß. Sei doch mal ehrlich; du wolltest dich ein wenig aufspielen und mal dazugehören und hast eine alte Unit ausgerammt und sie einfach gepostet. Sollen sich doch die anderen die Mühe machen und zuerst die Unit durchgucken was sie so alles kann. Die 5 Minuten Arbeit für eine kleine Beschreibung wolltest du dir nicht machen.
 Hier muß ich Tino viel Lob für seine Menschenkenntnis zugestehen, weil er mich nicht zum Mod gemacht hat. Ich als Mod hätte dein Beitrag sofort gekillt. Wenn du dir nicht die Arbeit einer Beschreibung machen willst, denn darfst du auch nicht posten. Es geht mir hier nicht darum ob die Unit gut oder schlecht ist, sondern ob man eine Beschreibung mitliefert und eine kleine Hilfe._________________ Popov
 |  |  |  
| Luckie Ehemaliges Mitglied
 Erhaltene Danke: 1
 
 
 
 
 | 
Verfasst: Mo 08.12.03 14:43 
 
Dein Code ist auch übelst zu lesen. persönlich kann jeder den Programmierstil frönen den er will. Aber so bald Code für die Öffentlichkeit bestimmt ist (e.g. OpenSource), sollte man sich zu mindest etwas an geläufuge Konvetionen halten.
 Beispiel:
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 
 | function getvalue(s0:string):extended; begin
 if length(s0)<1 then raise EparserError.Create('syntax error');
 if length(s0)=1 then result:=StrToDbl(s0) else
 case s0[1] of
 'x':result:=parameter.x;
 'y':result:=parameter.y;
 'z':result:=parameter.z;
 else result:=StrToDbl(s0);
 end;
 end;
 |  Ein Chaos von Einrückungen und nicht Einrückungen. Wo fängt hier ein Block an und hört ein anderer auf?
 		                       Delphi-Quelltext 
 									| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 
 | function getvalue(s0: string): extended;begin
 if length(s0) < 1 then
 raise EparserError.Create('syntax error');
 if length(s0) = 1 then
 result := StrToDbl(s0)
 else
 case s0[1] of
 'x': result := parameter.x;
 'y': result := parameter.y;
 'z': result := parameter.z;
 else
 result := StrToDbl(s0);
 end;
 end;
 |  So sieht das ganze doch schon etwas übersichtlicher aus.
 Desweiteren, ein Kommantar an der ein oder andern Stelle wäre nicht zu verachten.
Allgemein zu dieser Sparte Ich würde es für sinnvoll halten hier einen StyleGuide einzuführen. das dürfte das Arbeiten mit dem Code sehr vereinfachen. Damit da jetzt keine große Diskussion entbrennt, wie was zu formatieren ist, schlage ich vor, dass  man sich zumindest grob an den Borland Object Pascal Style Guide  hält. Zu finden zum Beispiel hier: www.luckie-online.de...l/opstyleguide.shtml |  |  |  
| Chatfix 
          Beiträge: 1583
 Erhaltene Danke: 10
 
 Win 10, Win 8, Win 7, Win Vista, Win XP
 VB.net (VS 2015), MsSQL (T-SQL), HTML, CSS, PHP, MySQL
 
 | 
Verfasst: Mo 08.12.03 15:45 
 
Ich bin auch dafür das ein bischen übersichtlicher zu halten...
Gibts den StyleGuide auch in Deutsch, da viele Anfänger sicher mit dem Englisch nicht gut zurechtkommen, aber man gerade als Anfänger lernen sollte Übersicht reinzubringen!
 _________________Gehirn: ein Organ, mit dem wir denken, daß wir denken. - Ambrose Bierce |  |  |  |