Преобразование строки в математическое выражение и получение результата
- А чем отличается программист от простого смертного?
- Тем, что может дать ответ на вопрос, уже содержащий в себе сам ответ.
- Да, это как?
- Ну, например:
- сколько будет 2 x 2=4?
- TRUE
unit MathComponent;
interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, math;
type
TMathtype = (mtnil, mtoperator, mtlbracket, mtrbracket, mtoperand);
type
TMathOperatortype = (monone, moadd, mosub, modiv, momul, mopow);
type
pmathchar = ^Tmathchar;
TMathChar = recordcase mathtype: Tmathtype of
mtoperand:(data:extended);
mtoperator:(op:TMathOperatortype);
end;
type
TMathControl = class(TComponent)
private
input, output, stack: arrayof tmathchar;
fmathstring: string;
function getresult:extended;
function calculate(operand1,operand2,operator:Tmathchar):extended;
function getoperator(c:char):TMathOperatortype;
function getoperand(mid:integer;var len:integer):extended;
procedure processstring;
procedure convertinfixtopostfix;
function isdigit(c:char):boolean;
function isoperator(c:char):boolean;
function getprecedence(mop:TMathOperatortype):integer;
protectedpublishedproperty MathExpression:stringread fmathstring write fmathstring;
property MathResult:extended read getresult;
end;
procedureregister;
implementationfunction Tmathcontrol.calculate(operand1,operand2,operator:Tmathchar):extended;
begin
result:=0;
case operator.op of
moadd:
result:=operand1.data + operand2.data;
mosub:
result:=operand1.data - operand2.data;
momul:
result:=operand1.data * operand2.data;
modiv:
if (operand1.data<>0) and (operand2.data<>0) then
result:=operand1.data / operand2.data
else
result := 0;
mopow:
result:=power(operand1.data, operand2.data);
end;
end;
function Tmathcontrol.getresult:extended;
var
i:integer;
tmp1,tmp2,tmp3:tmathchar;
begin
convertinfixtopostfix;
setlength(stack,0);
for i:=0 to length(output)-1 dobeginif output[i].mathtype=mtoperand thenbegin
setlength(stack,length(stack)+1);
stack[length(stack)-1]:=output[i];
endelseif output[i].mathtype=mtoperator thenbegin
tmp1:=stack[length(stack)-1];
tmp2:=stack[length(stack)-2];
setlength(stack,length(stack)-2);
tmp3.mathtype:=mtoperand;
tmp3.data:=calculate(tmp2,tmp1,output[i]);
setlength(stack,length(stack)+1);
stack[length(stack)-1]:=tmp3;
end;
end;
result:=stack[0].data;
setlength(stack,0);
setlength(input,0);
setlength(output,0);
end;
function Tmathcontrol.getoperator(c:char):TMathOperatortype;
begin
result:=monone;
if c='+' then
result:=moadd
elseif c='*' then
result:=momul
elseif c='/' then
result:=modiv
elseif c='-' then
result:=mosub
elseif c='^' then
result:=mopow;
end;
function Tmathcontrol.getoperand(mid:integer;var len:integer):extended;
var
i,j:integer;
tmpnum:string;
begin
j:=1;
for i:=mid to length(fmathstring)-1 dobeginif isdigit(fmathstring[i]) thenbeginif j<=20 then
tmpnum:=tmpnum+fmathstring[i];
j:=j+1;
endelse
break;
end;
result:=strtofloat(tmpnum);
len:=length(tmpnum);
end;
procedure Tmathcontrol.processstring;
var
i:integer;
numlen:integer;
begin
i:=0;
numlen:=0;
setlength(output,0);
setlength(input,0);
setlength(stack,0);
fmathstring:='('+fmathstring+')';
setlength(input,length(fmathstring));
while i<=length(fmathstring)-1 dobeginif fmathstring[i+1]='(' thenbegin
input[i].mathtype:=mtlbracket;
i:=i+1;
endelseif fmathstring[i+1]=')' thenbegin
input[i].mathtype:=mtrbracket;
i:=i+1;
endelseif isoperator(fmathstring[i+1]) thenbegin
input[i].mathtype:=mtoperator;
input[i].op:=getoperator(fmathstring[i+1]);
i:=i+1;
endelseif isdigit(fmathstring[i+1]) thenbegin
input[i].mathtype:=mtoperand;
input[i].data:=getoperand(i+1,numlen);
i:=i+numlen;
end;
end;
end;
function Tmathcontrol.isoperator(c:char):boolean;
begin
result:=false;
if (c='+') or (c='-') or (c='*') or (c='/') or (c='^') then
result:=true;
end;
function Tmathcontrol.isdigit(c:char):boolean;
begin
result:=false;
if ((integer(c)> 47) and (integer(c)< 58)) or (c='.') then
result:=true;
end;
function Tmathcontrol.getprecedence(mop:TMathOperatortype):integer;
begin
result:=-1;
case mop of
moadd: result := 1;
mosub: result := 1;
momul: result := 2;
modiv: result := 2;
mopow: result := 3;
end;
end;
procedure Tmathcontrol.convertinfixtopostfix;
var
i,j,prec:integer;
begin
processstring;
for i:=0 to length(input)-1 dobeginif input[i].mathtype=mtoperand thenbegin
setlength(output,length(output)+1);
output[length(output)-1]:=input[i];
endelseif input[i].mathtype=mtlbracket thenbegin
setlength(stack,length(stack)+1);
stack[length(stack)-1]:=input[i];
endelseif input[i].mathtype=mtoperator thenbegin
prec:=getprecedence(input[i].op);
j:=length(stack)-1;
if j>=0 thenbeginwhile(getprecedence(stack[j].op)>=prec) and (j>=0) dobegin
setlength(output,length(output)+1);
output[length(output)-1]:=stack[j];
setlength(stack,length(stack)-1);
j:=j-1;
end;
setlength(stack,length(stack)+1);
stack[length(stack)-1]:=input[i];
end;
endelseif input[i].mathtype=mtrbracket thenbegin
j:=length(stack)-1;
if j>=0 thenbeginwhile(stack[j].mathtype<>mtlbracket) and (j>=0) dobegin
setlength(output,length(output)+1);
output[length(output)-1]:=stack[j];
setlength(stack,length(stack)-1);
j:=j-1;
end;
if j>=0 then
setlength(stack,length(stack)-1);
end;
end;
end;
end;
procedureregister;
begin
RegisterComponents('Samples', [TMathControl]);
end;
end.
Перевод текста на русский язык:
Это код на языке Pascal для компонента TMathControl, который может принимать строку, представляющую математическое выражение, разбирать его в промежуточное представление, вычислять выражение и возвращать результат.
Разбор кода:
В начале кода определены типы TMathtype, TMathOperatortype и pmathchar, которые используются для представления различных частей математического выражения.
Определен класс TMathControl, который имеет несколько методов для разбирания, вычисления и манипуляции математическим выражением.
Метод processstring принимает строку, представляющую математическое выражение в виде входного параметра, разбирает его в промежуточное представление и хранит в массиве input.
Метод convertinfixtopostfix конвертирует разбитое выражение из инфиксной записи (где операторы располагаются между операндами) в постфиксную запись (где операторы следуют за операндами).
Метод getresult вычисляет разбитое выражение, применяя операторы в правильном порядке, и возвращает результат.
Метод calculate выполняет фактическое арифметическое действие в зависимости от типа оператора.
Методы getoperator, getoperand, isoperator и isdigit используются как вспомогательные функции при процессе разбирания.
Код также определяет несколько дополнительных процедур и функций, таких как register, которая используется для регистрации компонента TMathControl в палитре компонентов Delphi.
Некоторые потенциальные улучшения и предложения:
Обработка ошибок: код не обрабатывает ошибки хорошо. Например, если входная строка является недопустимой или парсер встречает неожиданный токен, он просто крушится. Вам может потребоваться добавить блоки try-except для ловли и обработки этих ошибок.
Организация кода: код очень плотный и может быстрее стать более читаемым и поддерживаемым с помощью рефакторинга. Например, вы можете разделить логику разбирания на отдельный метод или модуль.
Выполнение: код использует массивы для хранения промежуточных результатов, что может привести к проблемам с производительностью для больших выражений. Вам может потребоваться рассмотреть использование более эффективных структур данных, таких как связанные списки или стэки.
Интерфейс пользователя: код не предоставляет пользовательский интерфейс для ввода математического выражения или просмотра результата. Вам может потребоваться добавить компонент GUI для взаимодействия с пользователем и отображения вывода.
В целом, это хороший старт для создания математического выражения разбирателя и вычислителя в Delphi. С некоторым рефакторингом и тестированием он может стать более robust и полезным инструментом.
Программист отличается от простого смертного тем, что может дать ответ на вопрос, уже содержащий в себе сам ответ, например: сколько будет 2 x 2=4? - TRUE.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.