unit uEvaluate; //kt and Eddie added entire unit 3/28/10 { This unit was created by Josh Code and uploaded to Planet Source Code.com All changed are noted. Reformatting for code appearance applied. ----------------------------------------------------------------- The expression must follow the following rules: There can''t be any spaces. The only operators supported are: ^,*,/,+,- There must be the same number of begin and end brackets. Only the round brackets can be used. All values must be valid constants. A "valid constant," for this program, is defined as a string with: - no characters besides "0".."9," up to one ".", up to one "-" at the beginning - the string must be at least one character in length - Exponential sections are not supported, however, the "E" character is supported by "StrToFloat." ie. "3.14E-10" is not supported by this program, but it is for Delphi's "StrToFloat" function. ----------------------------------------------------------------- The purpose of the program is to show how to evaluate a string The program evaluates an expression contained in a string to a single real number using order of operation. The program supports powers, multiplication, division, adding, and subtraction. You are free to copy and paste this code for educational use. If you want it for commercial use, contact me. If you find some bugs, contact me. If you make any good improvements, contact me. I'd like to know if the code can be reduced. My email address is greijos@hotmail.com. A string is evaluated by finding the first simple expression to evaluate using order of operation (B.E.D.M.A.S.) Each operation is evaluated by looking at the operator character and getting the values on the left and right side of it. These values are found by scanning the characters to the left and right of the operator. After an operation is evaluated, the new value is substituted into the string and the next operation will then be evaluated. After evaluating all of the operations in the string, a single real number should remain. } {$O-} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,Math, StrUtils; function StringEval(str1: string;var problem: boolean): real; implementation function LastIndexOf(ch: char;str1: string): integer; var c: integer; begin result:=-1; // if the loop doesn't get a match then this is the result for c:=Length(str1) downto 1 do begin if str1[c]=ch then begin // if the character matches the character in the string result:=c; break; // don't continue the loop end; end; end; function GetClosingBracket(start1: integer; str1: string;var done: boolean): integer; var x: integer; ch: char; BCount: integer; begin done:=true; result:=0; BCount:=1; for x:=start1+1 to length(str1) do begin ch:=str1[x]; if (ch=')') or (ch='(') then begin case ch of '(': inc(BCount); ')': dec(BCount); end; if BCount=0 then begin done:=false; result:=x; break; end; end; end; end; function GetHigherBracket(const str1: string;var done,problem: boolean;var start1,end1: integer): string; var pos1,pos2: integer; begin // problem getting the higherbracket information when str1='(-1)*(-2)' result:=''; // initial value pos1:=pos('(',str1); start1:=pos1-1; pos2:=GetClosingBracket(pos1,str1,done); inc(pos2); end1:=pos2; if done then result:=str1 else if (pos1>0) xor (pos2>0) then begin ShowMessage('problem with getting brackets out of this string: "'+str1+'"'); problem:=true; end // there has to be a match between the number of end and beginning brackets else if Pos1>0 then result:=copy(str1,pos1+1,pos2-pos1-2) else begin // if there was no brackets in the string done:=true; result:=str1; end; end; //kt original --> function GetLeftNum(index1: integer;str1: string;var start1: integer; problem: boolean): real; function GetLeftNum(index1: integer;str1: string;var start1: integer; var problem: boolean): real; var c: integer; ch1: char; decimaled: boolean; // true after a decimal was added to NumStr NumStr: string; // a string to contain the number in string form until it is comletely copied begin // get the number left of a certain character by looping down the string result:=0; if index1=1 then begin result:=0; exit; end; NumStr:=''; // initialize string Decimaled:=false; for c:=index1-1 downto 1 do begin // loop down the string ch1:=str1[c]; if (ch1>='0')and(ch1<='9') then NumStr:=ch1+NumStr else if ch1='.' then begin if Decimaled then begin Problem:=true; Break; end else begin NumStr:=ch1+NumStr; end; Decimaled:=true; end else if ch1='-' then begin if c>1 then begin // avoid error when referring to a character that doesn't exist if (str1[c-1]<'0')or(str1[c-1]>'9') then begin // make sure the '-' is not supposed to be a subtraction operator NumStr:=NumStr+ch1; end; end else begin// first character of the string is added NumStr:=ch1+NumStr; end; Break; end else Break; end; start1:=c; { //kt if NumStr='' then problem:=true else result:=strtofloat(NumStr); } if NumStr='' then problem:=true; if not problem then begin result:=strtofloat(NumStr); end; end; //kt original --> function GetRightNum(index1: integer;str1: string;var end1: integer;problem: boolean): real; function GetRightNum(index1: integer;str1: string;var end1: integer; var problem: boolean): real; var c: integer; ch1: char; decimaled: boolean; // true after a decimal was added to NumStr NumStr: string; // a string to contain the number in string form until it is comletely copied begin // get the number left of a certain character by looping down the string NumStr:=''; // initialize string Decimaled:=false; for c:=index1+1 to Length(str1) do begin // loop down the string ch1:=str1[c]; if (ch1>='0')and(ch1<='9')or((c=index1+1)and(ch1='-')) then begin NumStr:=NumStr+ch1 end else if ch1='.' then begin if Decimaled then begin Problem:=true; Break; end else begin NumStr:=NumStr+ch1; end; Decimaled:=true; end else Break; end; if NumStr='' then problem:=true; if not problem then begin result:=strtofloat(NumStr); end else begin result := 0; end; end1:=c; { //kt if NumStr='' then problem:=true else result:=strtofloat(NumStr); end1:=c; } end; procedure SubstituteStr(StartIndex,EndIndex: integer;var str1: string;const SubStr: string); // substitute a substring into another string, replacing a certain index range var s1: string; begin s1:=''; if startindex<>1 then begin s1:=copy(str1,1,StartIndex); end; s1:=s1+SubStr; if EndIndex0) and (not problem) do begin// there is an adding operation to evaluate StoreOpVals(pos1,str1,problem,val1,val2,st1,en1); SubstituteStr(st1,en1,str1,floattostr(power(val1,val2))); end; while (Pos('*',str1)>0)or(Pos('/',str1)>0) and (not problem) do begin pos2:=Pos('*',str1); pos1:=Pos('/',str1); if (pos11)or(pos2<1) then begin StoreOpVals(pos1,str1,problem,val1,val2,st1,en1); SubstituteStr(st1,en1,str1,floattostr(val1/val2)); end else begin StoreOpVals(pos2,str1,problem,val1,val2,st1,en1); SubstituteStr(st1,en1,str1,floattostr(val1*val2)); end; end; while (Pos('+',str1)>0)or(Pos('-',str1)>0) and (not problem) do begin pos2:=pos('-',str1); if pos2=1 then // ie. str1 = '-4-4' pos2:=pos('-',copy(str1,2,999))+1; pos1:=Pos('+',str1); if pos2=1 then // ie. str1 = '+4-4' pos1:=pos('+',copy(str1,2,999))+1; if ((pos11) or (pos2<1)) then begin StoreOpVals(pos1,str1,problem,val1,val2,st1,en1); SubstituteStr(st1,en1,str1,floattostr(val1+val2)); end else if pos2>1 then begin// don't evaluate something like '-3423' StoreOpVals(pos2,str1,problem,val1,val2,st1,en1); SubstituteStr(st1,en1,str1,floattostr(val1-val2)); end else break; end; if (str1<>'') and not problem then begin //kt added problem check try result:=StrToFloat(str1); except on EConvertError do begin result := 0; problem := true; end; end; end else begin result := 0; problem := true; end; end; { procedure TForm1.Button1Click(Sender: TObject); var // Evaluate Expression s: string; problem: boolean; // used to hold information on a problem begin Problem:=false; s:=edit1.text; s:=floattostr(StringEval(s,problem)); if problem then edit1.text:='error' else edit1.text:=s; end; procedure TForm1.Button2Click(Sender: TObject); begin // Expression Guidelines // the character, #13, creates a new line. ShowMessage('The expression must follow the following rules:'+#13+ ' There can''t be any spaces.'+#13+ ' The only operators supported are: ^,*,/,+,-'+#13+ ' There must be the same number of begin and end brackets.'+#13+ ' Only the round brackets can be used.'+#13+ ' All values must be valid constants.'+#13+ ' A "valid constant," for this program, is defined as a string with:'+#13+ ' - no characters besides "0".."9," up to one ".", '+#13+ ' up to one "-" at the beginning'+#13+ ' - the string must be atleast one character in length'+#13+ ' - Exponential sections are not supported, however, the "E" character'+#13+ ' is supported by "StrToFloat." ie. "3.14E-10" is not supported by this program,'+#13+ ' but it is for Delphi''s "StrToFloat" function.' ); end; } end.