文字列を式として評価して結果を返す(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に表示されます。
