Delphi编程中,如何在可执行程序中执行四则运算

Delphi编程中,有时我们需要在编译完后的可执行程序中执行四则运算,这是好多年前用过的,现把它整理出来供大家使用,算计形式如下图所示:calc

 

调用方法如下代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  c:TCalcer;
begin
  c := TCalcer.Create;
  Edit2.Text := c.Calc(Edit1.Text);
  c.Free;
end;
下面是用与四则运算类的定义,提取至某第三方控件,将下列代码另存为Calc.pas文件后,再在工程中调用。

{ ****************************************** }
{                                            }
{ 四则运算的类                                }
{                                            }
{                                            }
{                                  tansoo.cn }
{                                     2005.3 }
{ ****************************************** }

unit Calc;

interface

uses Classes, Variants, SysUtils;

type
  TGetPValueEvent = procedure(const s: String; var v: Variant) of object;
  TFunctionEvent = procedure(const Name: String; p1, p2, p3: Variant;
    var Val: Variant) of object;

  TCalcer = class
  private
    FOnGetValue: TGetPValueEvent;
    FOnFunction: TFunctionEvent;
    function GetIdentify(const s: String; var i: Integer): String;
    function GetString(const s: String; var i: Integer): String;
    procedure Get3Parameters(const s: String; var i: Integer;
      var s1, s2, s3: String);
  public
    function Str2OPZ(s: String): String;
    function CalcOPZ(const s: String): Variant;
    function Calc(const s: String): Variant;
    property OnGetValue: TGetPValueEvent read FOnGetValue write FOnGetValue;
    property OnFunction: TFunctionEvent read FOnFunction write FOnFunction;
  end;

  TVariables = class(TObject)
  private
    FList: TStringList;
    procedure SetVariable(const Name: String; Value: Variant);
    function GetVariable(const Name: String): Variant;
    procedure SetValue(Index: Integer; Value: Variant);
    function GetValue(Index: Integer): Variant;
    procedure SetName(Index: Integer; Value: String);
    function GetName(Index: Integer): String;
    function GetCount: Integer;
    procedure SetSorted(Value: Boolean);
    function GetSorted: Boolean;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Assign(Value: TVariables);
    procedure Clear;
    procedure Delete(Index: Integer);
    function IndexOf(const Name: String): Integer;
    procedure Insert(Position: Integer; const Name: String);
    property Variable[const Name: String]
      : Variant read GetVariable write SetVariable; default;
    property Value[Index: Integer]: Variant read GetValue write SetValue;
    property Name[Index: Integer]: String read GetName write SetName;
    property Count: Integer read GetCount;
    property Sorted: Boolean read GetSorted write SetSorted;
  end;

  TFunctionSplitter = class
  protected
    FMatchFuncs, FSplitTo: TStrings;
    FParser: TCalcer;
    FVariables: TVariables;
  public
    constructor Create(MatchFuncs, SplitTo: TStrings; Variables: TVariables);
    destructor Destroy; override;
    procedure Split(s: String);
  end;

function GetBrackedVariable(const s: String; var i, j: Integer): String;

implementation

type
  PVariable = ^TVariable;

  TVariable = record
    Value: Variant;
  end;

const
  ttGe = #1;
  ttLe = #2;
  ttNe = #3;
  ttOr = #4;
  ttAnd = #5;
  ttInt = #6;
  ttFrac = #7;
  ttUnMinus = #9;
  ttUnPlus = #10;
  ttStr = #11;
  ttNot = #12;
  ttMod = #13;
  ttRound = #14;

function GetBrackedVariable(const s: String; var i, j: Integer): String;
var
  c: Integer;
  fl1, fl2: Boolean;
begin
  j := i;
  fl1 := True;
  fl2 := True;
  c := 0;
  Result := '';
  if (s = '') or (j > Length(s)) then
    Exit;
  Dec(j);
  repeat
    Inc(j);
    if fl1 and fl2 then
      if s[j] = '[' then
      begin
        if c = 0 then
          i := j;
        Inc(c);
      end
      else if s[j] = ']' then
        Dec(c);
    if fl1 then
      if s[j] = '"' then
        fl2 := not fl2;
    if fl2 then
      if s[j] = '''' then
        fl1 := not fl1;
  until (c = 0) or (j >= Length(s));
  Result := Copy(s, i + 1, j - i - 1);
end;

{ TVariables }

constructor TVariables.Create;
begin
  inherited Create;
  FList := TStringList.Create;
  FList.Duplicates := dupIgnore;
end;

destructor TVariables.Destroy;
begin
  Clear;
  FList.Free;
  inherited Destroy;
end;

procedure TVariables.Assign(Value: TVariables);
var
  i: Integer;
begin
  Clear;
  for i := 0 to Value.Count - 1 do
    SetVariable(Value.Name[i], Value.Value[i]);
end;

procedure TVariables.Clear;
begin
  while FList.Count > 0 do
    Delete(0);
end;

procedure TVariables.SetVariable(const Name: String; Value: Variant);
var
  i: Integer;
  p: PVariable;
begin
  i := IndexOf(Name);
  if i <> -1 then
    PVariable(FList.Objects[i]).Value := Value
  else
  begin
    New(p);
    p^.Value := Value;
    FList.AddObject(Name, TObject(p));
  end;
end;

function TVariables.GetVariable(const Name: String): Variant;
var
  i: Integer;
begin
  Result := Null;
  i := IndexOf(Name);
  if i <> -1 then
    Result := PVariable(FList.Objects[i]).Value;
end;

procedure TVariables.SetValue(Index: Integer; Value: Variant);
begin
  if (Index < 0) or (Index >= FList.Count) then
    Exit;
  PVariable(FList.Objects[Index])^.Value := Value;
end;

function TVariables.GetValue(Index: Integer): Variant;
begin
  Result := 0;
  if (Index < 0) or (Index >= FList.Count) then
    Exit;
  Result := PVariable(FList.Objects[Index])^.Value;
end;

function TVariables.IndexOf(const Name: String): Integer;
begin
  Result := FList.IndexOf(Name);
end;

procedure TVariables.Insert(Position: Integer; const Name: String);
begin
  SetVariable(Name, 0);
  FList.Move(FList.IndexOf(Name), Position);
end;

function TVariables.GetCount: Integer;
begin
  Result := FList.Count;
end;

procedure TVariables.SetName(Index: Integer; Value: String);
begin
  if (Index < 0) or (Index >= FList.Count) then
    Exit;
  FList[Index] := Value;
end;

function TVariables.GetName(Index: Integer): String;
begin
  Result := '';
  if (Index < 0) or (Index >= FList.Count) then
    Exit;
  Result := FList[Index];
end;

procedure TVariables.Delete(Index: Integer);
var
  p: PVariable;
begin
  if (Index < 0) or (Index >= FList.Count) then
    Exit;
  p := PVariable(FList.Objects[Index]);
  Dispose(p);
  FList.Delete(Index);
end;

procedure TVariables.SetSorted(Value: Boolean);
begin
  FList.Sorted := Value;
end;

function TVariables.GetSorted: Boolean;
begin
  Result := FList.Sorted;
end;

{ TCalcer }
{$WARNINGS OFF}

function TCalcer.CalcOPZ(const s: String): Variant;
var
  i, j, k, i1, st, ci, cn: Integer;
  s1, s2, s3, s4: String;
  nm: Array [1 .. 32] of Variant;
  v: Double;
begin
  st := 1;
  i := 1;
  nm[1] := 0;
  Result := 0;
  while i <= Length(s) do
  begin
    j := i;
    case s[i] of
      '+':
        nm[st - 2] := nm[st - 2] + nm[st - 1];
      ttOr:
        nm[st - 2] := nm[st - 2] or nm[st - 1];
      '-':
        nm[st - 2] := nm[st - 2] - nm[st - 1];
      '*', ttAnd:
        nm[st - 2] := nm[st - 2] * nm[st - 1];
      '/':
        if nm[st - 1] <> 0 then
          nm[st - 2] := nm[st - 2] / nm[st - 1]
        else
          nm[st - 2] := 0;
      '>':
        if nm[st - 2] > nm[st - 1] then
          nm[st - 2] := 1
        else
          nm[st - 2] := 0;
      '<':
        if nm[st - 2] < nm[st - 1] then
          nm[st - 2] := 1
        else
          nm[st - 2] := 0;
      '=':
        if nm[st - 2] = nm[st - 1] then
          nm[st - 2] := 1
        else
          nm[st - 2] := 0;
      ttNe:
        if nm[st - 2] <> nm[st - 1] then
          nm[st - 2] := 1
        else
          nm[st - 2] := 0;
      ttGe:
        if nm[st - 2] >= nm[st - 1] then
          nm[st - 2] := 1
        else
          nm[st - 2] := 0;
      ttLe:
        if nm[st - 2] <= nm[st - 1] then
          nm[st - 2] := 1
        else
          nm[st - 2] := 0;
      ttInt:
        begin
          v := nm[st - 1];
          if Abs(Round(v) - v) < 1E-10 then
            v := Round(v)
          else
            v := Int(v);

          nm[st - 1] := v;
        end;
      ttFrac:
        begin
          v := nm[st - 1];
          if Abs(Round(v) - v) < 1E-10 then
            v := Round(v);

          nm[st - 1] := Frac(v);
        end;
      ttRound:
        nm[st - 1] := Integer(Round(nm[st - 1]));
      ttUnMinus:
        nm[st - 1] := -nm[st - 1];
      ttUnPlus:
        ;
      ttStr:
        begin
          if nm[st - 1] <> Null then
            s1 := nm[st - 1]
          else
            s1 := '';
          nm[st - 1] := s1;
        end;
      ttNot:
        if nm[st - 1] = 0 then
          nm[st - 1] := 1
        else
          nm[st - 1] := 0;
      ttMod:
        nm[st - 2] := nm[st - 2] mod nm[st - 1];
      ' ':
        ;
      '[':
        begin
          k := i;
          s1 := GetBrackedVariable(s, k, i);
          if Assigned(FOnGetValue) then
            FOnGetValue(s1, nm[st]);
          Inc(st);
        end
      else
      begin
        if s[i] = '''' then
        begin
          s1 := GetString(s, i);
          s1 := Copy(s1, 2, Length(s1) - 2);
          while Pos('''' + '''', s1) <> 0 do
            Delete(s1, Pos('''' + '''', s1), 1);
          nm[st] := s1;
          k := i;
        end
        else
        begin
          k := i;
          s1 := GetIdentify(s, k);
          if (s1 <> '') and (s1[1] in ['0' .. '9', '.', ',']) then
          begin
            for i1 := 1 to Length(s1) do
              if s1[i1] in ['.', ','] then
                s1[i1] := DecimalSeparator;
            nm[st] := StrToFloat(s1);
          end
          else if AnsiCompareText(s1, 'TRUE') = 0 then
            nm[st] := True
          else if AnsiCompareText(s1, 'FALSE') = 0 then
            nm[st] := False
          else if s[k] = '[' then
          begin
            s1 := 'GETARRAY(' + s1 + ', ' + GetBrackedVariable(s, k, i) + ')';
            nm[st] := Calc(s1);
            k := i;
          end
          else if s[k] = '(' then
          begin
            s1 := AnsiUpperCase(s1);
            Get3Parameters(s, k, s2, s3, s4);
            if s1 = 'COPY' then
            begin
              ci := StrToInt(Calc(s3));
              cn := StrToInt(Calc(s4));
              nm[st] := Copy(Calc(s2), ci, cn);
            end
            else if s1 = 'IF' then
            begin
              if Int(StrToFloat(Calc(s2))) <> 0 then
                s1 := s3
              else
                s1 := s4;
              nm[st] := Calc(s1);
            end
            else if s1 = 'STRTODATE' then
              nm[st] := StrToDate(Calc(s2))
            else if s1 = 'STRTOTIME' then
              nm[st] := StrToTime(Calc(s2))
            else if Assigned(FOnFunction) then
              FOnFunction(s1, s2, s3, s4, nm[st]);
            Dec(k);
          end
          else if Assigned(FOnGetValue) then
            FOnGetValue(AnsiUpperCase(s1), nm[st]);
        end;
        i := k;
        Inc(st);
      end;
    end;
    if s[j] in ['+', '-', '*', '/', '>', '<', '=', ttGe, ttLe, ttNe, ttOr,
      ttAnd, ttMod] then
      Dec(st);
    Inc(i);
  end;
  Result := nm[1];
end;
{$WARNINGS ON}

function TCalcer.GetIdentify(const s: String; var i: Integer): String;
var
  k, n: Integer;
begin
  n := 0;
  while (i <= Length(s)) and (s[i] <= ' ') do
    Inc(i);
  k := i;
  Dec(i);
  repeat
    Inc(i);
    while (i <= Length(s)) and not(s[i] in [' ', #13, '+', '-', '*', '/', '>',
      '<', '=', '(', ')', '[']) do
    begin
      if s[i] = '"' then
        Inc(n);
      Inc(i);
    end;
  until (n mod 2 = 0) or (i >= Length(s));
  Result := Copy(s, k, i - k);
end;

function TCalcer.GetString(const s: String; var i: Integer): String;
var
  k: Integer;
  f: Boolean;
begin
  k := i;
  Inc(i);
  repeat
    while (i <= Length(s)) and (s[i] <> '''') do
      Inc(i);
    f := True;
    if (i < Length(s)) and (s[i + 1] = '''') then
    begin
      f := False;
      Inc(i, 2);
    end;
  until f;
  Result := Copy(s, k, i - k + 1);
  Inc(i);
end;

procedure TCalcer.Get3Parameters(const s: String; var i: Integer;
  var s1, s2, s3: String);
var
  c, d, oi, ci: Integer;
begin
  s1 := '';
  s2 := '';
  s3 := '';
  c := 1;
  d := 1;
  oi := i + 1;
  ci := 1;
  repeat
    Inc(i);
    if s[i] = '''' then
      if d = 1 then
        Inc(d)
      else
        d := 1;
    if d = 1 then
    begin
      if s[i] = '(' then
        Inc(c)
      else if s[i] = ')' then
        Dec(c);
      if (s[i] = ',') and (c = 1) then
      begin
        if ci = 1 then
          s1 := Copy(s, oi, i - oi)
        else
          s2 := Copy(s, oi, i - oi);
        oi := i + 1;
        Inc(ci);
      end;
    end;
  until (c = 0) or (i >= Length(s));
  case ci of
    1:
      s1 := Copy(s, oi, i - oi);
    2:
      s2 := Copy(s, oi, i - oi);
    3:
      s3 := Copy(s, oi, i - oi);
  end;
  if c <> 0 then
    raise Exception.Create('');
  Inc(i);
end;

function TCalcer.Str2OPZ(s: String): String;
label 1;
var
  i, i1, j, p: Integer;
  stack: String;
  res, s1, s2, s3, s4: String;
  vr: Boolean;
  c: Char;

  function Priority(c: Char): Integer;
  begin
    case c of
      '(':
        Priority := 5;
      ')':
        Priority := 4;
      '=', '>', '<', ttGe, ttLe, ttNe:
        Priority := 3;
      '+', '-', ttUnMinus, ttUnPlus:
        Priority := 2;
      '*', '/', ttOr, ttAnd, ttNot, ttMod:
        Priority := 1;
      ttInt, ttFrac, ttRound, ttStr:
        Priority := 0;
    else
      Priority := 0;
    end;
  end;

  procedure ProcessQuotes(var s: String);
  var
    i: Integer;
  begin
    if (Length(s) = 0) or (s[1] <> '''') then
      Exit;
    i := 2;
    if Length(s) > 2 then
      while i <= Length(s) do
      begin
        if (s[i] = '''') and (i < Length(s)) then
        begin
          Insert('''', s, i);
          Inc(i);
        end;
        Inc(i);
      end;
  end;

begin
  res := '';
  stack := '';
  i := 1;
  vr := False;
  while i <= Length(s) do
  begin
    case s[i] of
      '(':
        begin
          stack := '(' + stack;
          vr := False;
        end;
      ')':
        begin
          p := Pos('(', stack);
          res := res + Copy(stack, 1, p - 1);
          stack := Copy(stack, p + 1, Length(stack) - p);
        end;
      '+', '-', '*', '/', '>', '<', '=':
        begin
          if (s[i] = '<') and (s[i + 1] = '>') then
          begin
            Inc(i);
            s[i] := ttNe;
          end
          else if (s[i] = '>') and (s[i + 1] = '=') then
          begin
            Inc(i);
            s[i] := ttGe;
          end
          else if (s[i] = '<') and (s[i + 1] = '=') then
          begin
            Inc(i);
            s[i] := ttLe;
          end;

        1 :
          if not vr then
          begin
            if s[i] = '-' then
              s[i] := ttUnMinus;
            if s[i] = '+' then
              s[i] := ttUnPlus;
          end;
          vr := False;
          if stack = '' then
            stack := s[i] + stack
          else if Priority(s[i]) < Priority(stack[1]) then
            stack := s[i] + stack
          else
          begin
            repeat
              res := res + stack[1];
              stack := Copy(stack, 2, Length(stack) - 1);
            until (stack = '') or (Priority(stack[1]) > Priority(s[i]));
            stack := s[i] + stack;
          end;
        end;
      ';':
        break;
      ' ', #13:
        ;
    else
      begin
        vr := True;
        s2 := '';
        i1 := i;
        if s[i] = '%' then
        begin
          s2 := '%' + s[i + 1];
          Inc(i, 2);
        end;
        if s[i] = '''' then
          s2 := s2 + GetString(s, i)
        else if s[i] = '[' then
        begin
          s2 := s2 + '[' + GetBrackedVariable(s, i, j) + ']';
          i := j + 1;
        end
        else
        begin
          s2 := s2 + GetIdentify(s, i);
          if s[i] = '[' then
          begin
            s2 := s2 + '[' + GetBrackedVariable(s, i, j) + ']';
            i := j + 1;
          end;
        end;
        c := s[i];
        if (Length(s2) > 0) and (s2[1] in ['0' .. '9', '.', ',']) then
          res := res + s2 + ' '
        else
        begin
          s1 := AnsiUpperCase(s2);
          if s1 = 'INT' then
          begin
            s[i - 1] := ttInt;
            Dec(i);
            goto 1;
          end
          else if s1 = 'FRAC' then
          begin
            s[i - 1] := ttFrac;
            Dec(i);
            goto 1;
          end
          else if s1 = 'ROUND' then
          begin
            s[i - 1] := ttRound;
            Dec(i);
            goto 1;
          end
          else if s1 = 'OR' then
          begin
            s[i - 1] := ttOr;
            Dec(i);
            goto 1;
          end
          else if s1 = 'AND' then
          begin
            s[i - 1] := ttAnd;
            Dec(i);
            goto 1;
          end
          else if s1 = 'NOT' then
          begin
            s[i - 1] := ttNot;
            Dec(i);
            goto 1;
          end
          else if s1 = 'STR' then
          begin
            s[i - 1] := ttStr;
            Dec(i);
            goto 1;
          end
          else if s1 = 'MOD' then
          begin
            s[i - 1] := ttMod;
            Dec(i);
            goto 1;
          end
          else if c = '(' then
          begin
            Get3Parameters(s, i, s2, s3, s4);
            res := res + Copy(s, i1, i - i1);
          end
          else
            res := res + s2 + ' ';
        end;
        Dec(i);
      end;
    end;
    Inc(i);
  end;
  if stack <> '' then
    res := res + stack;
  Result := res;
end;

function TCalcer.Calc(const s: String): Variant;
begin
  Result := CalcOPZ(Str2OPZ(s));
end;

{ TFunctionSplitter }

constructor TFunctionSplitter.Create(MatchFuncs, SplitTo: TStrings;
  Variables: TVariables);
begin
  inherited Create;
  FParser := TCalcer.Create;
  FMatchFuncs := MatchFuncs;
  FSplitTo := SplitTo;
  FVariables := Variables;
end;

destructor TFunctionSplitter.Destroy;
begin
  FParser.Free;
  inherited Destroy;
end;

procedure TFunctionSplitter.Split(s: String);
var
  i, k: Integer;
  s1, s2, s3, s4: String;
begin
  i := 1;
  s := Trim(s);
  if (Length(s) > 0) and (s[1] = '''') then
    Exit;
  while i <= Length(s) do
  begin
    k := i;
    if s[1] = '[' then
    begin
      s1 := GetBrackedVariable(s, k, i);
      if FVariables.IndexOf(s1) <> -1 then
        s1 := FVariables[s1];
      Split(s1);
      k := i + 1;
    end
    else
    begin
      s1 := FParser.GetIdentify(s, k);
      if s[k] = '(' then
      begin
        FParser.Get3Parameters(s, k, s2, s3, s4);
        Split(s2);
        Split(s3);
        Split(s4);
        if FMatchFuncs.IndexOf(s1) <> -1 then
          FSplitTo.Add(Copy(s, i, k - i));
      end
      else if FVariables.IndexOf(s1) <> -1 then
      begin
        s1 := FVariables[s1];
        Split(s1);
      end
      else if s[k] in [' ', #13, '+', '-', '*', '/', '>', '<', '='] then
        Inc(k)
      else if s1 = '' then
        break;
    end;
    i := k;
  end;
end;

end.

/* 表达式计算 */ /* 调用方式:CalcExp('1+max(0.5,sin(1))+sum(1,2^3,mod(5,3))', res, infoStr) */ /* 带符号参数调用方法,先调用符号定义AddSignParam,再调用 CalcExp: */ /* AddSignParam(['a','s'], [1, 0.5]); 或者 AddSignParam('a=1,s=0.5') */ /* CalcExp('1+a+sin(s)', res, infoStr) */ /* 其res存储计算结果,为double型;infoStr存储计算时的提示信息,为string */ 表达式计算器 V2.3 支持以下功能: 1、四则运算 + - * / 、括弧()、正负(+ -) 2、百分数 %、求幂 ^ 、整数阶乘 ! (1 至 150) 3、参数符号计算,示例:a+b @@a=1,b=2 结算结果为3 用@@表示表达式定义符号的值 4、常数e、圆周率PI 5、丰富的函数功能: 统计函数: max,min,sum,avg,stddev 标准偏差,均支持多参数 三角函数: sin,cos,tan,arcsin,arccos,arctan degrad(60) 角度转弧度 raddeg(3.14) 弧度转角度 costh(a,b,c) 余弦定理 cosC) 指数对数函数:sqrt,power(x,y),abs,exp,log2,log10,logN(a,N),ln 数据处理函数:int(x),trunc(x) 取整 frac(x) 取小数部分 round(x) 四舍五入取整 roundto(x,-1) 保留一位小数 mod(M,N) 求模 几何面积函数:s_tria(a,b,c) 三角形面积 s_circ(r) 圆形面积 s_elli(a,b) 椭圆面积 s_rect(a,b) 矩形面积 s_poly(a,n) 正多边形面积 平面几何函数:pdisplanes(x1,y1,x2,y2) 平面两点距离 pdisspace(x1,y1,z1,x2,y2,z2) 空间两点 p_line(x0,y0, A, B, C) 平面点到线距离 p_planes(x0,y0,z0 A, B, C, D)空间点到面距离 数列求和: sn(a1, d, n) 等差数列前n项和 sqn(a1, q, n) 等比数列前n项和 个税计算函数:intax(x), arcintax(x) 个税反算 6 、历史计算记录,双击计算记录可重新修改计算 示例: sin(1)+(-2+(3-4))*20% , e^63+PI , 15! , log2(max(2,3)) 注: 运算符必须为半角格式,三角函为弧度,输入可用空格间隔
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值