für ein aktuelles Projekt brauchte ich eine Funktion die Terme die als String angegeben werden ausrechnen kann. Da so etwas bestimmt jeder mal gebrauchen kann stelle ich diese für euch zur freien Verfügung.
Ist zwar in Delphi geschrieben, aber wer nicht grade vollends blöd ist sollte das einfach in andere Sprachen übersetzten können.
Das ganze kennt die befehle +, -, *, /, sowie POW was für hoch steht, und ROOT was für wurzel steht (So ist 2 POW 3 also 2³ und 2 ROOT 4 die quadratwurzel (2te wurzel) aus 4)
Es werden multiple klammer ebenen unterstützt, aber wichtig ist dass operatoren und zahlen durch leerstellen getrennt sind, d.h. 3+2 ist nicht gültig, 3 + (1 + 2) schon
Vllt baue ich noch ein paar sachen wie sinus und cosinus ein, aber so funktioniert es vorerst schon recht gut (auch wenn es wohl nicht die performanteste lösung ist)
Code:
uses Math;
type
TOperator = (opNil, opAdd, opSub, OpMulti, OpDiff, opPow, opRoot);
PValue = ^TValue;
TValue = record
Op: TOperator;
Val: Real;
end;
function Evaluate(Inp: string): Real;
procedure Calc(ValLst: TList; i: Integer);
var
val1, val2: PValue;
z: Integer;
begin
val1 := ValLst[i];
val2 := ValLst[i + 1];
if (val1^.Op = opAdd) or (val1^.Op = opSub) then
begin
if (val2^.Op = OpMulti) or (val2^.Op = OpDiff) or (val2^.Op = opRoot) or
(val2^.Op = opPow) then
Calc(ValLst, i + 1);
end
else if (val1^.Op = OpMulti) or (val1^.Op = OpDiff) then
begin
if (val2^.Op = opRoot) or (val2^.Op = opPow) then
Calc(ValLst, i + 1);
end;
case val1^.Op of
opAdd:
begin
val1^.Op := val2^.Op;
val1^.Val := val1^.Val + val2^.Val;
end;
opSub:
begin
val1^.Op := val2^.Op;
val1^.Val := val1^.Val - val2^.Val;
end;
OpMulti:
begin
val1^.Op := val2^.Op;
val1^.Val := val1^.Val * val2^.Val;
end;
OpDiff:
begin
val1^.Op := val2^.Op;
val1^.Val := val1^.Val / val2^.Val;
end;
opPow:
begin
val1^.Op := val2^.Op;
val1^.Val := Power(val1^.Val, val2^.Val);
end;
opRoot:
begin
val1^.Op := val2^.Op;
val1^.Val := Power(val2^.Val, 1 / val1^.Val);
end;
end;
Dispose(ValLst[i + 1]);
ValLst.Delete(i + 1);
end;
function IsFloat(S: string): boolean;
var
f: extended;
begin
Result := TextToFloat(PChar(S), f, fvExtended);
end;
function Eval(str: string; var i: Integer): Real;
var
tmp: string;
Vals: TList;
x: Integer;
tmpVal: PValue;
begin
Vals := TList.Create;
tmpVal := nil;
try
// Zwischenspeicher
tmp := '';
repeat
inc(i);
// Wenn leer, nach einem operator oder zahl des terms
if (str[i] = ' ') then
begin
// Wenn es ein Operator ist
if tmp = '+' then
begin
tmpVal^.Op := opAdd;
end
else if tmp = '-' then
begin
tmpVal^.Op := opSub;
end
else if tmp = '*' then
begin
tmpVal^.Op := OpMulti;
end
else if tmp = '/' then
begin
tmpVal^.Op := OpDiff;
end
else if tmp = 'POW' then
begin
tmpVal^.Op := opPow;
end
else if tmp = 'ROOT' then
begin
tmpVal^.Op := opRoot;
end
else if IsFloat(tmp) then // Wenn es eine zahl ist (zahl immer vor op)
begin
if not Assigned(tmpVal) then
new(tmpVal); // Neue Value erstellen
tmpVal^.Val := StrToFloat(tmp); // zahl setzen
tmpVal^.Op := opNil; // Operator auf nil
end;
if Assigned(tmpVal) then // wenn zahl erstellt
if (tmpVal^.Op <> opNil) then // Und operator gesetzt
begin
Vals.Add(tmpVal); // Zur liste hinzufügen
tmpVal := nil;
end;
tmp := '';
end
else if str[i] = '(' then // Bei Subterm
begin
if tmpVal = nil then
new(tmpVal); // Neue Value erstellen
tmpVal^.Val := Eval(str, i); // zahl setzen
inc(i);
tmpVal^.Op := opNil; // Operator auf nil
end
else if str[i]<>')' then
tmp := tmp + str[i];
if ((i = Length(str)) or (str[i] = ')')) then
begin
if IsFloat(tmp) then
begin
if not Assigned(tmpVal) then
new(tmpVal); // Neue Value erstellen
tmpVal^.Val := StrToFloat(tmp); // zahl setzen
tmpVal^.Op := opNil; // Operator auf nil
end;
if Assigned(tmpVal) then
Vals.Add(tmpVal);
end;
until ((str[i] = ')') Or (i > Length(str))); // wiederholen für jedes zeichen bis subterm oder zeilen ende
// Rechenen
repeat
x := 0;
repeat
Calc(Vals, x);
inc(x);
until (x >= Vals.Count - 2);
until (Vals.Count = 1);
Result := PValue(Vals[0])^.Val;
finally
for x := 0 to Vals.Count - 1 do
Dispose(Vals[x]);
Vals.Free;
end;
end;
var
i: Integer;
begin
i := 0;
result:=Eval(Inp, i);
end;
[VB08]String in String mit mehreren Funden 08/08/2011 - .NET Languages - 6 Replies Hey,
bin gerade auf ein Problem gestoßen, an dem ich mir seit 3 Stunden die Zähne ausbeiße.
Ich will eine Funktion schreiben, die der _StringBetween Funktion von AutoIt gleich ist. _StringBetween gibt in einem Array alle Strings zwischen zwei SubStrings und dem ganzen String aus. Die Ausgabe bei
_StringBetween("<h1>test1</h1>&l t;h1>test2</h1>", "<h1>", "</h1>") wäre also idealer Weiße ein Array (x = "test1", x = "test2")...
da man in VB08 kein Array returnen kann, komme ich aber einfach...
Den Term in einem String ausrechnen 08/07/2009 - AutoIt - 3 Replies $variable="17*8+123*3*4-13/1"
Msgbox(0,"test",$variable)
Wäre nett wenn mir jemand helfen könnte :
Ich will nicht dass der ganze String in der Textbox gezeigt wird sondern nur das Ergebnis , gibt es dazu ne UDF oder etwas ähnliches ? habe mich schon zu Tode gesucht ...
P.S.
Bitte kommt mir nicht mit "Das kann man doch sicher auch anders machen" ,"man muss es doch nicht unbedingt als String speichern" .