トップへ(mam-mam.net/)

文字列を式として評価して結果を返す(eval関数) ~Delphiソースコード集

検索:

文字列を式として評価して結果を返す(eval関数) ~Delphiソースコード集

TBindingExpressionを使うと入力した文字列、例えば "(10+3)*4/3" を式として評価して結果を返すことができます。
しかし、E(定数)、Sqrt、Sin、Cos、Tan、Abs、Exp、Log10、Pow、Round、RoundUp、RoundDown等は使えないので拡張して使ってみます。
参考URL
https://qiita.com/pik/items/e888e52b4fa2f70a419f
https://qiita.com/pik/items/8384a7b9a04f3e628e71

プロジェクトの作成

[ファイル]⇒[新規作成]⇒[Windows VCL アプリケーション -Delphi] をクリックします。
TEditと、TMemoを配置します。

ソースコードの記述

Edit1をクリックし、左下ペインの「オブジェクト インスペクタ」の「イベント」タブを選択します。
「OnKeyPress」の右側の空白をダブルクリックしてソースコードを記述します。
(Edit1がアクティブで、キーボードのキーを押したとき)

全体のソースコードは以下になります。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Memo1: TMemo;
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

function eval(st:String):String;

implementation

{$R *.dfm}

uses System.Bindings.Helper, System.Bindings.Expression,
     System.Bindings.EvalSys, System.Bindings.EvalProtocol,
     System.Bindings.Methods, System.Math;

function eval(st:String):String;
var be : TBindingExpression;
    DSE:TDictionaryScope;
    SSqrt,SSin,SCos,STan,SAbs:TPairScope;
    SExp,SLog10,SPow:TPairScope;
    SRound,SRoundUp,SRoundDown:TPairScope;
begin
  //Pi 円周率はデフォルトで定数定義されている
  //E  自然対数の底を定数定義する
  DSE := TDictionaryScope.Create;
  DSE.Map.Add('E', TValueWrapper.Create(Exp(1)));

  //Sqrt(平方根)
  SSqrt := TPairScope.Create(
    'Sqrt',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V:Extended;
      begin
        V := Args[0].GetValue.AsExtended;
        V := Sqrt(V);
        Result := TValueWrapper.Create(V);
      end
    )
  );
  //Sin  サイン
  SSin := TPairScope.Create(
    'Sin',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V:Extended;
      begin
        V := Args[0].GetValue.AsExtended;
        V := Sin(V);
        Result := TValueWrapper.Create(V);
      end
    )
  );
  //Cos  コサイン)
  SCos := TPairScope.Create(
    'Cos',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V:Extended;
      begin
        V := Args[0].GetValue.AsExtended;
        V := Cos(V);
        Result := TValueWrapper.Create(V);
      end
    )
  );
  //Tan  タンジェント
  STan := TPairScope.Create(
    'Tan',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V:Extended;
      begin
        V := Args[0].GetValue.AsExtended;
        V := Cos(V);
        Result := TValueWrapper.Create(V);
      end
    )
  );
  //Abs  絶対値
  SAbs := TPairScope.Create(
    'Abs',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V:Extended;
      begin
        V := Args[0].GetValue.AsExtended;
        V := Abs(V);
        Result := TValueWrapper.Create(V);
      end
    )
  );
  //Exp  e(自然対数)の X 乗)
  SExp := TPairScope.Create(
    'Exp',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V:Extended;
      begin
        V := Args[0].GetValue.AsExtended;
        V := Exp(V);
        Result := TValueWrapper.Create(V);
      end
    )
  );
  //lLog10  10を底とする対数
  SLog10 := TPairScope.Create(
    'Log10',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V:Extended;
      begin
          V := Args[0].GetValue.AsExtended;
          Result := TValueWrapper.Create(Log10(V));
      end
    )
  );
  //Pow(b, e)  bのe乗
  SPow := TPairScope.Create(
    'Pow',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V1,V2:Extended;
      begin
          V1 := Args[0].GetValue.AsExtended;
          V2 := Args[1].GetValue.AsExtended;
          Result := TValueWrapper.Create(Power(V1,V2));
      end
    )
  );
  //Round(v, [d=0])  vのd桁目を四捨五入
  SRound := TPairScope.Create(
    'Round',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V1:Extended;
          V2:Integer;
      begin
          V1 := Args[0].GetValue.AsExtended;
          if Length(Args)=2 then
            V2 := Args[1].GetValue.AsInteger
          else
            V2:=0;
          Result := TValueWrapper.Create(RoundTo(V1,V2));
      end
    )
  );
  //RoundUp(v, [d=0])  vのd桁目を切り上げ
  SRoundUp := TPairScope.Create(
    'RoundUp',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V1:Extended;
          V2:Integer;
      begin
          V1 := Args[0].GetValue.AsExtended;
          if Length(Args)=2 then
            V2 := Args[1].GetValue.AsInteger
          else
            V2:=0;
          V1:=Ceil(V1/Power(10,V2));
          V1:=V1*Power(10,V2);
          Result := TValueWrapper.Create(V1);
      end
    )
  );
  //RoundDown(v, [d=0])  vのd桁目を切り捨て
  SRoundDown := TPairScope.Create(
    'RoundDown',
    MakeInvokable(
      function(Args: TArray<IValue>): IValue
      var V1:Extended;
          V2:Integer;
      begin
          V1 := Args[0].GetValue.AsExtended;
          if Length(Args)=2 then
            V2 := Args[1].GetValue.AsInteger
          else
            V2:=0;
          V1:=Floor(V1/Power(10,V2));
          V1:=V1*Power(10,V2);
          Result := TValueWrapper.Create(V1);
      end
    )
  );
  be := TBindings.CreateExpression(
    [DSE,SSqrt,SSin,SCos,STan,SAbs,SExp,SLog10,SPow,SRound,SRoundUp,SRoundDown],
    st
  );
  try
    try
      result:=be.Evaluate.GetValue.AsExtended.ToString;
    except
      result:='err';
    end;
  finally
    be.Free;
  end;
end;


procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  if Key=#13 then
  begin
    Memo1.Lines.Add(Eval(Edit1.Text));
  end;
end;

end.

実行する

実行して、Edit1に、
Sin( 45/180*Pi )
を入力して、キーボードのEnterキーを押すと計算結果がMemo1に表示されます。