计算公式(50分)

  • 主题发起人 主题发起人 牛哥168
  • 开始时间 开始时间

牛哥168

Unregistered / Unconfirmed
GUEST, unregistred user!
假设有一个计算公式
D=(A+B)*C
在edit1 输入A
在edit2 输入B
在edit3 输入C
在edit4 输入 (A+B)*C (计算公式)
在edit5 输出D
也就是如何应用自定义公式的问题
 
写函数解析edit4的表达式,如果是A用Edit1的内容代替. 依此类推
 
以前收集的一个,有点长,不过应该用的上

unit EditExp;

{
EditExp Ver 1.00

Expression Evaluator
by Ricardo Barrenechea Compuserve 73050,261
Internet RBarre@spi-cis.com

}

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Grids;

type
TEditExp = class(TEdit)
private
{ Private declarations }
protected
{ Protected declarations }

FValue : double
{ Value of expression}
FSValue : string
{ Value of expression - string}
FMask : string
{ Mask to convert FValue to FSValue}

FError : integer
{ Number of Error}

FVarGrid : TStringGrid
{ TStringGrid where to read Var's}
FUseVar : boolean
{ Use Var's ?}
FExp : string
{ Expression without Var's}


{ Get Functions for Properties}
function GetValue : double;
function GetSValue : string;
function GetExp : string;


{ Set Procedure for properties}
procedure SetMask(value :string);
procedure SetVarGrid(value:TStringGrid);
procedure SetUseVar(value:boolean);

{ Protected Methods}
procedure Calc
{ CORE !}
procedure ChangeVar
{ Internal to Change Var's to their values}


public
{ Public declarations }
constructor Create(AOwner:TComponent)
override;
destructor Destroy
override;


{ Public Methods}
function Error : boolean
{ True or false}
function GetError : string
{ Error string}


{ Public Properties}
property Value : double read GetValue
{ VALUE }
property SValue : string read GetSValue
{ STRING}
property Exp : string read GetExp
{ EXPRESSION}

published
{ Published declarations }
property Mask : string read FMask write SetMask;
property VarGrid : TStringGrid read FVarGrid write SetVarGrid;
property UseVar : boolean read FUseVar write SetUseVar;
end;


{ Global FUNCTION !}
function Evaluate(formula: string
var status,location: integer) : double;

procedure Register;


implementation


{================================== EVALUATE ================================}
{ ------------------------------- Declarations ----------------------------- }

const MaxReal = 1.0E+37
{ Maximum real value that we will allow }
MaxFact = 33
{ 33! = E+37 }
MaxExpo = 85
{ exp(85) = E+37 }



var Region, { Check if result is defined. eg fact(-1.2) }
Divzero, { Check if a division by zero occured. eg 1/0 }
Overflow, { Check if result becomes too large. eg 100! }
Complex : boolean
{ Check if result is complex. eg sqrt(-1) }


{ -------------------------------------------------------------------------- }



constructor TEditExp.Create(AOwner:TComponent);
begin
inherited Create(AOwner);

{ No Error, No Var's, No Grid}
FError:=0;
FUseVar:=false;
FVarGrid:=nil;
end;


destructor TEditExp.Destroy;
begin
inherited Destroy;
end;


procedure TEditExp.ChangeVar;
var i,k : integer;
CellVar : string;

begin
{ Change Var's labels with Var's values}
with FVarGrid do
begin
if (ColCount>2) and (RowCount>1) then
begin
i:=1;
while (i<RowCount) and (Cells[1,i]<>'') do
begin
CellVar:='['+UpperCase(Cells[1,i])+']';

{ All the ocurrences of CellVar in Expression}
repeat
k:=Pos(CellVar, FExp);

if k>0 then
begin
delete(FExp, k, length(CellVar) );
insert(Cells[2,i], FExp, k);
end;
until k=0;

Inc(i);

end
{while}
end
{if}
end
{with}
end;

procedure TEditExp.Calc;
var cod,loc : integer;
begin
FExp:=UpperCase(Text);
if (FUseVar) and (FVarGrid<>nil) then
begin
ChangeVar;
end;

{ I don't use loc [location of Error] (till now)}
FValue:=Evaluate(FExp,cod,loc)
{ CORE !!!}
if cod<>0 then FValue:=0;
FError:=cod;
end;

{
GetValue GetExp & GetSValue
first do CALC
It can be done in a diferent way !
}
function TEditExp.GetValue : double;
begin
Calc;
GetValue :=FValue;
end;

function TEditExp.GetExp : string;
begin
Calc;
GetExp :=FExp;
end;

function TEditExp.GetSValue: string;
begin
Calc;
GetSValue :=FormatFloat(FMask,FValue);
end;

function TEditExp.GetError : string;
var s: string;
begin
Case FError of
0: s:=' No error ';
1: s:=' Illegal character';
2: s:=' Incorrect syntax';
3: s:=' Illegal or missing parenthese';
4: s:=' Incorrect real format';
5: s:=' Illegal function';
6: s:=' Result is undefined';
7: s:=' Result is too large';
8: s:=' Result is complex';
9: s:=' Division by zero';
end;
GetError:=s;
end;


procedure TEditExp.SetMask(value :string);
begin
FMask:=value;
end;

function TEditExp.Error : boolean;
begin
Error:= (FError<>0);
end;

procedure TEditExp.SetVarGrid(value:TStringGrid);
begin
FVarGrid:=value;
end;

procedure TEditExp.SetUseVar(value:boolean);
begin
FUseVar:=value;
end;

procedure Register;
begin
RegisterComponents('Samples', [TEditExp]);
end;



{============================================================================}
{================================== EVALUATE ================================}
{ From a VERY VERY OLD Pascal 3.0 Function !
{============================================================================}


{ Initialize boolean flags. }
procedure Init_Booleans;
begin
region:=true
{ Result is initially inside region }
complex:=false
{ Result is not complex }
divzero:=false
{ There is no division by zero }
overflow:=false
{ and no overflow. }
end
{ Init_Booleans }



{ Check to see if doing an operation on a and b will cause an overflow and
set the OVERFLOW boolean accordingly }

procedure CheckOverflow(a,b: real
operation: char);
begin
case operation of
'*': if abs(a) > 1.0 then overflow:=abs(b) > MaxReal/abs(a);
'/': if b <> 0.0 then
begin
b:=1/b;
if abs(a) > 1.0 then overflow:=abs(b) > MaxReal/abs(a)
end
else overflow:=true;
'+': if b > 0.0 then overflow:=a > (MaxReal - b)
else overflow:=a < (-MaxReal - b);
'-': if b < 0.0 then overflow:=a > (MaxReal + b)
else overflow:=a < (-MaxReal + b);
else overflow:=true
{ Default for bad operation }
end
{ case }
end
{ CheckOverflow }


{ ----------------------------------------------------------------------------
The following functions -- asin,acos,tan,cot,sec,csc,sinh,cosh,tanh,sech,
csch,coth,fact -- will default to 0.0 if a division by zero occurs, the
result is complex or undefined, or if an overflow occurs.

If you are using these functions independently of the Evaluate procedure
then the procedure Init_Booleans should be called first to reinitialize
error checking.
---------------------------------------------------------------------------- }


{ --- Arc Sine --- }

function Asin(r: real): real;
begin
if abs(r) < 1.0 then asin:=arctan(r/sqrt(1-r*r))
else
if abs(r) = 1.0 then asin:=(r/abs(r))*pi/2
else
begin
asin:=0.0;
complex:=true
end { else }
end
{ asin }

{ --- Arc Cosine --- }

function Acos(r: real): real;
begin
if r = 0.0 then acos:=pi/2
else
begin
if abs(r) < 1.0 then
begin
if r < 0.0 then acos:=arctan(sqrt(1-r*r)/r)+pi
else acos:=arctan(sqrt(1-r*r)/r)
end
else
if abs(r) = 1.0 then
if r = 1.0 then acos:=0.0
else acos:=pi
else
begin
acos:=0.0;
complex:=true
end
end
end
{ acos }

{ --- Tangent --- }

function Tan(r: real): real;
begin
if cos(r) = 0.0 then
begin
tan:=0.0;
divzero:=true
end
else tan:=sin(r)/cos(r)
end
{ tan }

{ --- CoTangent --- }

function Cot(r: real): real;
begin
if sin(r) = 0.0 then
begin
cot:=0.0;
divzero:=true
end
else cot:=cos(r)/sin(r)
end
{ cot }

{ --- Secant --- }

function Sec(r: real): real;
begin
if cos(r) = 0.0 then
begin
sec:=0.0;
divzero:=true
end
else sec:=1/cos(r)
end
{ Sec }

{ --- CoSecant --- }

function Csc(r: real): real;
begin
if sin(r) = 0.0 then
begin
csc:=0.0;
divzero:=true
end
else csc:=1/sin(r)
end
{ Csc }

{ --- Sinh --- }

function Sinh(r: real): real;
begin
if abs(r) <= MaxExpo then sinh:=(exp(r)-exp(-r))/2
else
begin
overflow:=true;
sinh:=0.0
end
end
{ Sinh }

{ --- CoSinh --- }

function Cosh(r: real): real;
begin
if abs(r) <= MaxExpo then cosh:=(exp(r)+exp(-r))/2
else
begin
overflow:=true;
cosh:=0.0
end
end
{ Cosh }

{ --- Tanh --- }

function Tanh(r: real): real;
begin
if cosh(r) = 0.0 then
begin
tanh:=0.0;
divzero:=true
end
else
begin
CheckOverflow(sinh(r),cosh(r),'/');
if not overflow then tanh:=sinh(r)/cosh(r)
else tanh:=0.0
end
end
{ Tanh }

{ --- Sech --- }

function Sech(r: real): real;
begin
if cosh(r) = 0.0 then
begin
sech:=0.0;
divzero:=true
end
else
begin
CheckOverflow(1,cosh(r),'/');
if not overflow then sech:=1/cosh(r)
else sech:=0.0
end
end
{ Sech }

{ --- CoSech --- }

function Csch(r: real): real;
begin
if sinh(r) = 0.0 then
begin
csch:=0.0;
divzero:=true
end
else
begin
CheckOverflow(1,sinh(r),'/');
if not overflow then csch:=1/sinh(r)
else csch:=0.0
end
end
{ Csch }

{ --- CoTanh --- }

function Coth(r: real): real;
begin
if sinh(r) = 0.0 then
begin
coth:=0.0;
divzero:=true
end
else
begin
CheckOverflow(cosh(r),sinh(r),'/');
if not overflow then coth:=cosh(r)/sinh(r)
else coth:=0.0
end
end
{ Coth }

{ --- Factorial --- }

function Fact(r:real): real;
var i: integer;
resulta: real;
begin
if (r < 0.0) or (trunc(r) <> r) then
begin
resulta:=0.0;
region:=false
end
else
begin
resulta:=1.0;
if trunc(r) < MaxFact then
for i:=1 to trunc(r) do
resulta:=resulta*i
else
begin
overflow:=true;
resulta:=0.0
end
end;
fact:=resulta
end
{ Fact }


{ ----------------------------------------------------------------------------
The function Evaluate is passed a mathematical expression in the form of a
string (formula) to be evaluated and returns the following:

If no errors occur during evaluation then:
Result = evaluated expression
Status = 0
Location = 0

If an error occurs then:
Result = 0.0
Status = error type
Location = location of error in formula

Error types:
0: No error occured
1: Illegal character
2: Incorrect syntax
3: Illegal or missing parenthese
4: Incorrect real format
5: Illegal function
6: Result is undefined
7: Result is too large
8: Result is complex
9: Division by zero

---------------------------------------------------------------------------- }


function Evaluate(formula: string
var status,location: integer):double;

{ ---- Declaration ---- }

const numbers: set of char = ['0'..'9']
{ Digits }
RightPar: set of char = [')',']','}']
{ Right parentheses }
LeftPar: set of char = ['(','[','{']
{ Left parentheses }
alpha: set of char = ['A'..'Z']
{ Alpha characters }
operators: set of char = ['+','-','*','/','^']
{ Operators }
eofline = ^M;

var ch: char
{ Current character }
resulto: real
{ Final value }

{ ---- Internal routines ---- }

{ Check to see if an error has occured }
function Ok: boolean;
begin
ok:= region and (not divzero) and (not complex)
and (not overflow) and (status = 0);
end
{ Ok }

{ Get the next character in the string and increment the location pointer. }
procedure NextCh;
begin
repeat
location:=location+1
{ Increment pointer }
if location <= length(formula) then ch:=formula[location]
else ch:=eofline;
if not (ch in alpha + numbers + LeftPar + RightPar + operators
+ ['.',' ','!',eofline]) then
status:=1
{ Illegal char. }
until ch <> ' '
{ Skip blanks }
end { NextCh };


{ ---- Nested functions ---- }


function Expression: real;
label quit;
var e,e_hold: real;
opr: char;
Leading_Sign,Nested_Function: boolean;


function SimpleExpression: real;
label quit;
var s,s_hold: real;
opr: char;


function Term: real;
label quit;
var t,t_hold: real;


function SignedFactor: Real;


function Factor: Real;
label quit;
type StandardFunction =
(fpi,fabs,fsqrt,fsqr,fln,flog,fexp,ffact,
fsinh,fcosh,ftanh,fsech,fcsch,fcoth,
fsin,fcos,ftan,fsec,fcsc,fcot,fasin,facos,fatan);

StandardFunctionList = array[StandardFunction] of string[4];

const StandardFunctionNames: StandardFunctionList =
('PI','ABS','SQRT','SQR','LNG','LOG','EXP','FACT',
'SINH','COSH','TANH','SECH','CSCH','COTH',
'SIN','COS','TAN','SEC','CSC','COT','ASIN','ACOS','ATAN');

var Found: Boolean;
l: integer;
F: Real;
str: string;
Sf: StandardFunction;
start,position: integer;

begin { Function Factor }

{ Exit if error }
if not ok then begin f:=0.0
goto quit end;

{ Get a real or integer expression }
if ch in numbers+['.'] then
begin
start:=location;
if ch in numbers then repeat NextCh until not (ch in numbers);
if ch = '.' then repeat NextCh until not (ch in numbers);

{ Get the E format of a real expression }
if ch = 'E' then
begin
NextCh;
if ch = 'X' then location:=location - 1 { Skip EXP(...) }
else
if not (ch in numbers + ['+','-']) then status:=4
else repeat NextCh until not (ch in numbers);
end;

{ Check the real format }
str:=copy(formula,start,location-start);

{ Remove all spaces in str otherwise val will bomb! }
while pos(' ',str) <> 0 do delete(str,pos(' ',str),1);

val(str,f,position);
if position <> 0 then
begin
location:=start+position;
status:=4 { Incorrect Real format }
end;
end { end if ch in number }

{ The character is not a digit }
else
begin

{ Check for for the beginning of a &quot;sub&quot
expression }
if ch in LeftPar then
begin
NextCh;
F:=Expression
{ RECURSION !!! }
if ok and (ch in RightPar) then { Check for implicit * }
begin
NextCh;
if not (ch in operators+LeftPar+RightPar+['!',eofline]) then
begin
ch:='*';
location:=location-1
end;
end
else status:=3 { Illegal parenthese }
end { if ch in LeftPar }

{ It should be a function }
else
begin
found:=false;

{ Search for the function among our list }
for sf:=fpi to fatan do
if not found then
begin
l:=length(StandardFunctionNames[sf]);

if copy(formula,location,l)=StandardFunctionNames[sf] then
begin
location:=location+l-1;
NextCh;
if sf <> fpi then
begin
Nested_Function:=true;
F:=Factor
end;

{ Assign values according to the function }
case sf of
fpi: f:=pi
{ pi is predefined }
fsqr: if f < 1.0e+19 then f:=sqr(f)
else
begin
f:=0.0;
overflow:=true
end;
fabs: f:=abs(f);
fsqrt: if f < 0.0 then
begin
complex:=true;
f:=0.0
end
else f:=sqrt(f);

fsin: f:=sin(f);
fcos: f:=cos(f);
ftan: f:=tan(f);
fasin: f:=asin(f);
facos: f:=acos(f);
fatan: f:=arctan(f);
fsec: f:=sec(f);
fcsc: f:=csc(f);
fcot: f:=cot(f);

fsinh: f:=sinh(f);
fcosh: f:=cosh(f);
ftanh: f:=tanh(f);
fsech: f:=sech(f);
fcsch: f:=csch(f);
fcoth: f:=coth(f);

fexp: if abs(f) < MaxExpo then f:=exp(f)
else
if f < 0 then f:=0.0
else
begin
overflow:=true;
f:=0.0
end;
ffact: f:=fact(f);
fln : if f < 0.0 then
begin
complex:=true;
f:=0.0
end
else
if f = 0.0 then
begin
overflow:=true;
f:=0.0
end
else f:=ln(f);
flog: if f < 0.0 then
begin
complex:=true;
f:=0.0
end
else
if f = 0.0 then
begin
overflow:=true;
f:=0.0
end
else f:=ln(f)/ln(10);
end
{ Case }

found:=true;
Nested_Function:=false;

{ Check for a trailing factorial symbol }
if ch = '!' then
begin
f:=fact(f);
NextCh
end

end { If copy = function }
end
{ If not found }

{ Check for more errors }
if (not found) and ok and not (ch in alpha) then
status:=2
{ Illegal Syntax }
if (not found) and ok and (ch in alpha) then
status:=5
{ Illegal function }

end { Else not ch in LeftPar .. ie. it should be a function }
end
{ else the character is not a digit }

{ Check for a trailing factorial symbol }
if ok and (not Nested_Function) and (ch = '!') then
begin
f:=fact(f);
NextCh
end;

{ Assign final value }
quit: Factor:=F
end
{ Factor inside SignedFactor }

begin { SignedFactor }
if ch = '-' then
begin
NextCh;
SignedFactor:= -Factor
end
else SignedFactor:=Factor;
end { SignedFactor inside Term };


begin { Term }
if not ok then begin t:=0.0
goto quit end
{ Exit }

t:=SignedFactor;
while ch = '^' do
begin
if not ok then begin t:=0.0
goto quit end
{ Exit }

NextCh;
t_hold:=SignedFactor;

{ Check for illegal power }
if ((t < 0.0) and ((t_hold-trunc(t_hold)) <> 0.0)) or (t = 0.0) then
begin
t:=0.0;
complex:=true
end

{ Power is legal }
else
begin
if t < 0.0 then
begin
CheckOverflow(ln(-t),t_hold,'*');
if not Ok then begin t:=0.0
goto quit end
{ Exit }

if ln(-t)*t_hold <= MaxExpo then
case trunc(abs(t_hold)) mod 2 = 0 of
true: t:=exp(ln(-t)*t_hold);
false: t:=-exp(ln(-t)*t_hold)
end
else
begin
t:=0.0;
overflow:=true
end
end { if t < 0.0 }

else { t >= 0.0 }
begin
CheckOverflow(ln(t),t_hold,'*');
if not Ok then begin t:=0.0
goto quit end
{ Exit }

if ln(t)*t_hold <= MaxExpo then t:=exp(ln(t)*t_hold)
else
begin
t:=0.0;
overflow:=true
end
end { else t >= 0.0 }
end { else not illegal power }
end
{ while }
quit: Term:=t;
end
{ Term inside SimpleExpression }


begin { SimpleExpression }
if not ok then begin s:=0.0
goto quit end
{ Exit }
s:=term;

{ Check for implicit multiplication and insert missing &quot;*&quot
}
if ok and (ch in LeftPar + alpha + numbers + ['.']) then
begin
ch:='*';
location:=location-1
end;

while ch in ['*','/'] do
begin
if not ok then begin s:=0.0
goto quit end
{ Exit }
opr:=ch;
NextCh;

{ Check for implicit multiplication and insert missing &quot;*&quot
}
if opr in LeftPar + alpha + numbers + ['.'] then
begin
opr:='*';
ch:='(';
location:=location-1
end;

s_hold:=term;
case opr of
'*': begin
CheckOverflow(s,s_hold,'*');
if not overflow then s:=s*s_hold
else s:=0.0
end;
'/': begin
divzero:=s_hold = 0.0;
if not divzero then
begin
CheckOverflow(s,s_hold,'/');
if not overflow then s:=s/s_hold
else s:=0.0
end
else s:=0.0
end
end
{ Case }

{ Check for implicit multiplication and insert missing &quot;*&quot
}
if ok and (ch in LeftPar + alpha + numbers + ['.']) then
begin
ch:='*';
location:=location-1
end
end
{ while }

{ Assign final value }
quit: SimpleExpression:=s;
end
{ SimpleExpression inside Expression }


begin { Expression }
if not ok then begin e:=0.0
goto quit end
{ Exit }
Nested_Function:=false;

Leading_Sign:= ch = '-'
{ The default is + }
if ch in ['+','-'] then Nextch
{ Skip leading sign }
case Leading_Sign of { Set for leading sign }
true: e:= -SimpleExpression;
false: e:= SimpleExpression
end;

while ch in ['+','-'] do
begin
if not ok then begin e:=0.0
goto quit end
{ Exit }
opr:=ch;
NextCh;

e_hold:=SimpleExpression;
case opr of
'+': begin
CheckOverflow(e,e_hold,'+');
if not overflow then e:=e+e_hold
else e:=0.0;
end;
'-': begin
CheckOverflow(e,e_hold,'-');
if not overflow then e:=e-e_hold
else e:=0.0;
end;
end
{ case }
end
{ while }
quit: Expression:=e;
end
{ Expression inside Evaluate }

var i:integer;

begin { Evaluate }

{ Initialize }
for i:=1 to length(formula) do
formula:=upcase(formula);
Init_Booleans;
status:=0;
location:=0;
NextCh;

{ Get result }
resulto:=Expression;

{ Check for final errors }
if ok then if ch <> eofline then status:=2
{ Incorrect Syntax }

if not region then status:=6;
if overflow then status:=7;
if complex then status:=8;
if divzero then status:=9;

if status in [4,6..9] then location:=location-1;
if status = 0 then location:=0
else resulto:=0.0;

Evaluate:=resulto;
end { Evaluate };

end.
 
uses StrUtils, ComObj;

procedure TForm1.Button1Click(Sender: TObject);
var
vScript : Variant;
s: string;
begin
s:=Edit4.Text;
s:=AnsiReplacetext(s,'A',Edit1.Text);
s:=AnsiReplacetext(s,'B',Edit2.Text);
s:=AnsiReplacetext(s,'C',Edit3.Text);
try
vScript := CreateoleObject('scriptcontrol');
vScript.language := 'javascript';
Edit5.Text := vScript.eval(s);
except
ShowMessage('公式错误 !');
end;
end;
 
我整理的这个( TSpeedParser )可以添加自定义变量的:P
请看: http://www.delphibbs.com/delphibbs/dispq.asp?lid=3419067

节约空间,代码就不贴了。
 
大家都是高人啊!!!
谢谢大家
kaida的方法简单实用
 

Similar threads

回复
0
查看
1K
不得闲
D
回复
0
查看
825
DelphiTeacher的专栏
D
D
回复
0
查看
831
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部