Duplicate
Is there a built-in Delphi function which would convert a string such as '2*x+power(x,2)' or any equation to float? StrToFloat raises an exception because of the char X and power.
Thanks.
Is there a built-in Delphi function which would convert a string such as '2*x+power(x,2)' or any equation to float? StrToFloat raises an exception because of the char X and power.
Thanks.
The free JCL includes TEvaluator, a parser written by one of the current Delphi compiler engineers. It will likely be far more efficient than an expression evaluator based on Windows Script Host.
Long ago (iirc 2005), some SIG did an comparison of various expression parsers. The results are at:
http://www.mindspring.com/~rbwinston/ParserTestFiles.zip
including the classic Turbo Pascal one by Renate Schaaf.
In general, the faster ones generate native code, but are unportable, and might need fixing for DEP etc.
Writing a basic one yourself isn't that hard, and a standard task in many programming courses. I wrote one in FPC/Delphi (now part of the freepascal distribution as "Symbolic") and converted it later to Java (as an exercise in Java string handling. I still wake up screaming at night sometimes).
Its SVN location is
http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/symbolic/
Note to self: I still have some unfinished code somewhere to add user definable functions and boolean arithmetic. Must finish it someday :-)
You are looking for something that can evaluate an expression.
Since Delphi is a compiled language, it does not have built-in support for that.
However, there are external tools that can help you with that.
For instance: the Free Pascal Scripting engine from RemObjects can do what you want.
--jeroen
No, it's impossible except of parsing string. And how can you convert unknown number x to float?
In our SMImport suite we wrote the own expression parser/evaluator which is based on original TFatExpression component by Gasper Kozak, gasper.kozak@email.si
Works very good.
You can use my unit, its still basic but im still writing it, it does basic bodmas right now but i will post the whole unit when i am done
Unit BODMAS;
Interface
Uses
System.SysUtils,
Math;
{
!!!!!!!!!!!!!!!!!!!!!! GLOBAL DEFINITIONS !!!!!!!!!!!!!!!!!!!!
EXPR = EXPRESSION
CURRENTPOS = POSSITION OF THE CURRENT OPPERATOR OF WHICH MATH IS BEING PERFORMED
}
Function EvalFunction(Expr: String): String;
Implementation
Function PrevOppPos(Expr: String; CurrentPos: Integer): Integer; // GETS THE PREVIOUS OPPERATOR
Var
I: Integer;
bSet: Boolean;
Begin
// THEORY
// KEEP MOVING POSITIONS DOWN FROM I ... ( MEANING < WAY IN EXPR)
// UNTIL AN OPPERATOR IS FOUND. IF NO OPPERATOR IS FOUND THE RESULT
// WILL BE THE BEGINING OF THE EXPRESSION
I := CurrentPos - 1;
bSet := False;
While ((I <= CurrentPos) AND (I >= 1)) OR (bSet = False) Do
Begin
// CHECK IF THE CHACHARACTER OF POSITION I IN EXPR IS AN OPPERATOR
// "." AND "," IS NOT AN OPPERATOR!!
If Expr[I] In ['(', ')', '+', '-', 'x', '/'] Then
Begin
Result := I;
bSet := True;
Dec(I); // Dec 1 more time to break loop
End;
Dec(I);
If (I = 0) AND (NOT(bSet)) Then
Begin
Result := 1;
bSet := True;
End;
End;
End;
Function NextOppPos(Expr: String; CurrentPos: Integer): Integer;
Var
I: Integer;
bSet: Boolean;
Begin
// THEORY
// KEEP MOVING POSITIONS UP FROM I ... ( MEANING > WAY IN EXPR)
// UNTIL AN OPPERATOR IS FOUND. IF NO OPPERATOR IS FOUND THE RESULT
// WILL BE THE LENGHT OF THE EXPRESSION
I := CurrentPos + 1;
bSet := False;
While ((I <= Length(Expr)) AND (I >= CurrentPos)) OR (bSet = False) Do
Begin
// CHECK IF THE CHACHARACTER OF POSITION I IN EXPR IS AN OPPERATOR
// "." AND "," IS NOT AN OPPERATOR!!
If Expr[I] In ['(', ')', '+', '-', 'x', '/'] Then
Begin
Result := I;
bSet := True;
Inc(I); // Inc 1 more time to break loop
End;
Inc(I);
If (I = Length(Expr) + 1) AND (NOT(bSet)) Then
Begin
Result := Length(Expr);
bSet := True;
End;
End;
End;
// EVALUATE BRACKET EXPRESSION
Function EvalBracetExpr(Expr: String): String;
Var
OppCount, I: Integer;
Ans: String;
NewExpr: String;
nOpp, pOpp, OppPos: Integer;
nExpr, pExpr: String;
Begin
Ans := '';
// EVALUATE EXPRESSION
// ALL MULTIPLICATION IN BRACKETS
While Pos('x', Expr) <> 0 Do
Begin
OppPos := Pos('x', Expr); // Opperator Position
nOpp := NextOppPos(Expr, OppPos); // Next Opperator Position
pOpp := PrevOppPos(Expr, OppPos); // Previous Opperator Position
// COPY FROM THE OPPERATOR POS TO THE LENGTH OF THE EXPRESSION - THE POSITION OF THE NEXT EXPRESSION
// When Next opperator is the length of the expression
If nOpp = Length(Expr) Then
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - (Length(Expr) - 1))
Else
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - nOpp);
// COPY FROM THE PREVIOUS OPPERATOR POS TO THE OPPERATOR POSITION -1
pExpr := Copy(Expr, pOpp + 1, (OppPos - 1) - pOpp);
Delete(Expr, pOpp, nOpp);
Ans := Ans + FloatToStr(StrToFloat(pExpr) * StrToFloat(nExpr));
End;
// ALL ADDITION IN BRACKETS
While Pos('+', Expr) <> 0 Do
Begin
OppPos := Pos('+', Expr); // Opperator Position
nOpp := NextOppPos(Expr, OppPos); // Next Opperator Position
pOpp := PrevOppPos(Expr, OppPos); // Previous Opperator Position
// COPY FROM THE OPPERATOR POS TO THE LENGTH OF THE EXPRESSION - THE POSITION OF THE NEXT EXPRESSION
// When Next opperator is the length of the expression
If nOpp = Length(Expr) Then
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - (Length(Expr) - 1))
Else
nExpr := Copy(Expr, OppPos + 1, Length(Expr) - nOpp - 1);
// COPY FROM THE PREVIOUS OPPERATOR POS TO THE OPPERATOR POSITION -1
pExpr := Copy(Expr, pOpp + 1, (OppPos - 1) - pOpp);
Delete(Expr, pOpp, nOpp);
Ans := Ans + FloatToStr(StrToFloat(pExpr) + StrToFloat(nExpr));
End;
Result := Ans;
End;
// EVALUTE ADDITION EXPRESSION
Function EvalAddExpr(Expr: String): String;
Var
Expr1, Expr2: String;
Begin
Expr1 := Copy(Expr, 1, Pos('+', Expr) - 1);
Expr2 := Copy(Expr, Pos('+', Expr) + 1, Length(Expr));
Result := FloatToStr(StrToFloat(Expr1) + StrToFloat(Expr2));
End;
Function EvalFunction(Expr: String): String;
Var
bOPos, bCPos: Integer; // bracket Open/Closed Position
sExpr: String;
FinalExpr: String;
OppPos: Integer;
PrevOpp, NextOpp: Integer;
Begin
While Pos('(', Expr) <> 0 Do
Begin
// Find first open bracket
bOPos := Pos('(', Expr);
// Find first closed bracket
bCPos := Pos(')', Expr);
// Get the expression between the 2 brackets
sExpr := Copy(Expr, bOPos, bCPos);
// Remove sExpr from the Expression
Delete(Expr, bOPos, bCPos + 1 - bOPos);
// Concatenate the expression of what was before the bracket and that after the bracket, as well as the result in the middle
FinalExpr := Copy(Expr, 1, bOPos - 1) + EvalBracetExpr(sExpr) + Copy(Expr, bOPos, Length(Expr));
// Return the result
Expr := FinalExpr;
End;
While Pos('+', Expr) <> 0 Do
Begin
// 1) Find the first + opperator in expression
OppPos := Pos('+', Expr);
// 2) find first part of expression
PrevOpp := PrevOppPos(Expr, OppPos);
// 3) find the next part of the expression
NextOpp := NextOppPos(Expr, OppPos);
// 4) get the full expression between the opperators
//
// if prev opp <> 1 then
// move indicator 1 pos ahead
If PrevOpp <> 1 Then
Inc(PrevOpp);
// if next opp <> len of expr then
// move indicator 1 pos back
If NextOpp <> Length(Expr) Then
Dec(NextOpp);
sExpr := Copy(Expr, PrevOpp, NextOpp);
// 5) evaluating expression
Delete(Expr, PrevOpp, NextOpp);
FinalExpr := Copy(Expr, 1, PrevOpp-1) + EvalAddExpr(sExpr) + Copy(Expr, PrevOpp, Length(Expr));
End;
Result := Expr;
End;
End.
you will use the EvalFunction to return results