Получение результата математического выражения из строки

Рейтинг: 0Ответов: 1Опубликовано: 10.07.2023

Есть ли возможность реализовать следующую концепцию? В поле TextEdit задается математическое выражение, например 2*2+2. При нажатии на кнопку (или любое другое событие), поле калькулируется и получается результат 6, которое вставляется в это же поле TextEdit.

Другими словами, существуют ли в Delphi методы, которые из строки вида математического выражения возвращают результат из этого выражения?

Ответы

▲ 2Принят

В общем, я нашёл где-то в закулисьях интернета один примечательный, но наверняка не совсем безопасный метод реализации данного компонента из коробки в VCL. Опишу его реализацию и работу.

Создадим VCL форму из двух компонентов, TEdit как edt1 и TButton как btn1, чисто для теста на событие.

введите сюда описание изображения

Внутри кода нужно дополнить секцию uses следующими модулями:

uses
...
System.Bindings.EvalProtocol,
System.Bindings.Evaluator,
System.Bindings.EvalSys,
System.Rtti
...

Из документации выяснил, что System.Bindings.EvalProtocol содержит интерфейсы для различных аспектов привязки данных, в том числе и скомпилированные выражения, а System.Bindings.Evaluator имеет в себе метод Compile, который может компилировать выражения с помощью оболочки IScope, возвращая ICompiledBinding, его же можно использовать для вычисления результата компиляции.

System.Bindings.EvalSys содержит в себе базовые операторы для работы с LiveBindings. System.Rtti в свою очередь содержит в себе классы, которые могут манипулировать классами объектов, что обеспечит более глубокую привязку во время выполнения кода.

Зная это, можно реализовать следующий код в событии на нажатие кнопки btn1:

procedure TForm1.btn1Click(Sender: TObject);
var
  expr:string;
  Result: Extended;
  LScope: IScope;
  LCompiledExpr: ICompiledBinding;
  LResult: TValue;
begin
  LScope:=BasicOperators;
  LCompiledExpr:=Compile(edt1.Text,LScope);
  LResult:=LCompiledExpr.Evaluate(LScope, nil, nil).GetValue;
  if not LResult.IsEmpty then
  begin
    edt1.Text:=LResult.ToString
  end;
end;

Здесь мы собственно производим компиляцию нашего выражения из строки, а далее получаем результат данной компиляции и выводим её как строку, если та не пуста.

Результат выглядит следующим образом:

  • Вводим выражение

введите сюда описание изображения

  • Нажимаем на кнопку и получаем результат

введите сюда описание изображения


UPD1

Изучв внутренности компонентов, пришёл к тому, что выражение может состоять только из сложения, вычитания, умножения, деления, отрицания, а так же из логических операторов сравнения, что в общем то делает дела безопаснее. System.Bindings.Evaluator имеет в себе следующие референсы:

...
// <summary>Enumeration for built-in operators. It is used internally by
  // the expression compiler.</summary>
  TBuiltinOp = (boAdd, boSubtract, boMultiply, boDivide, boNegate,
    boEqualTo, boNotEqual, boLessThan, 
    boLessEqual, boGreaterThan, boGreaterEqual);
...