Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.10.08;
Скачать: CL | DM;

Вниз

Калькулятор   Найти похожие ветки 

 
nstur   (2006-09-15 16:07) [0]

Подскажите методы или компоненты способные вычислять строковое выражение вводимое пользователем.
Типа: (20+10)/5


 
Ketmar ©   (2006-09-15 16:16) [1]

подсказываю метод: разобрать и вычислить.


 
MBo ©   (2006-09-15 16:20) [2]

в RXLib есть парсер


 
Cyrax ©   (2006-09-15 22:38) [3]

Есть кулькулятор такой интеллектуальный, виндовый.
Так что и компоненты не нужню....


 
Zeqfreed ©   (2006-09-15 22:48) [4]

http://www.google.com/search?q=(20%2B10)/5


 
AlexeyT ©   (2006-09-16 10:11) [5]

Ищи компоненты на Torry.net по словам: parser math expressions.


 
DprYg ©   (2006-09-16 10:16) [6]


> Есть кулькулятор такой интеллектуальный, виндовый.
Такой интеллектуальный, что для того чтобы вычислить какое-то выражение, нужно его перевести в спецкод, который написать в блокноте, скопировать в буфер, а затем  из него вставить в окно.


 
BorisMor ©   (2006-09-16 21:16) [7]

В постфиксную форму переводим и делаем что надо.
Вот мой самопальный модуль.


{Перевод в постфиксную форму (c) BorisMor

Описание с
http://alglib.sources.ru/expressions/tosimplerpn.php

Исходная формула  Польская запись
a+b               a b +
a+b*c             a b c * +
(a+b)*c           a b +c *
123*(a+b)*c       123 a b + * c *

1. Символ английского алфавита, значит мы имеем переменную - считываем ее имя и помещаем в результирующую строку.
2. Цифра, значит мы имеем число - считываем его полностью и помещаем в результирующую строку.
3. Открывающаяся скобка "(" - помещаем ее на стек.
4. Закрывающаяся скобка ")" - переносим операции со стека в результирующую строку
   до момента пока не сняли со стека "(", открывающуюся скобку в результат не помещаем.
   Если открывающаяся скобка так и не встретилась, значит в исходном выражение
   неправильно расставлены скобки помещаем в результат "ERROR" и выходим из алгоритма.
5. Операция "+","-","*","/" - переносим в результат операции с вершины стека до
   тех пор пока стек не пуст и приоритет текущей операции меньше либо равен
   приритету операции находящейся на вершине стеке. Затем помещаем текущую операцию на стек.
   a) если в стеке нет операций, операции кладётся в стек;
   b) если новая операции имеет больший приоритет , чем верхняя операции в
       стеке, то новая операции кладётся в стек;
   c) если новая операция имеет меньший или равный приоритет, чем верхняя
       операции в стеке, то все операции, находящиеся в стеке, перекладываются в
       формируемую запись, а новая операции кладётся в стек.

После окончанию переносим операции оставшиеся на
стеке в результат. Если на стеке осталась открывающаяся скобка, значит в
обрабатываемом выражении содержится ошибка, а следовательно помещаем в
результат ERROR
}
unit uPostfix;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Dialogs ;

type
TTypeChar = (tcNum, tcMath, tcOScob, tcCScob, tcOther);

// Вовзращает приоритет операции
function PriorityOper(ch: char): integer;

// Сравнивает операций: если приоритет newOp больше oldOp то возвращается true
function CmpOper(newOp, oldOp: char): boolean;

// Разбивает строку value на лексеммы и помещает их в список
procedure BreakLex(value: string; ListLex: TStringList);

// Вовзращает тип символа
function TypeChar(c: Char): TTypeChar;

// Перевести в постфиксную форму. Все лексеммы заносит в lsOut
procedure Postfix(value: string; lsOut: TStringList);

// Результат работы Postfix в виде строки
function PostfixStr(value: string): string;

// Добавляет в lsOut данные из lsIn под номером ind (строку и Objects)
procedure CopyLine(lsSource,lsOut: TStringList; ind: integer);

// Простейшая операция над двумя числамми
function SimplCalc (op1,op2: Extended ; act: string):Extended;

// Подсчет данныых записанных в строке
function calcul(value: string) :Extended;

implementation
////////////////////////////////////////////////////////////////////////////////
// Простейшая операция над двумя числамми
function SimplCalc (op1,op2: Extended ; act: string):Extended;
var
ch: Char;
begin
result := 0;
ch := act[1];
case ch of
   "+" : result := op1 + op2;
   "-" : result := op1 - op2;
   "/" : result := op1 / op2;
   "*" : result := op1 * op2;
end; {case}
end;
////////////////////////////////////////////////////////////////////////////////
// Подсчет данныых записанных в строке
function calcul(value: string) :Extended;
var
lst: TStringList;
i,j: integer;
b: boolean;
op1,op2, rez: Extended;
ch: char;
sRez: string;
begin
result := 0;
lst := TStringList.Create;
try
   Postfix(value, lst); // Переводим в постфиксный вид
   while lst.Count > 1 do
       begin
           i := 0;
           b := false;
           // Находим первую мат. операцию
           repeat
               b := TTypeChar(lst.Objects[i]) = tcMath;
               if not b then inc(i);
           until
             (i > lst.Count) or b;

           if b then // Нашли какую то операцию ==> берем идущие перед ней 2 числа и выполняем
               begin
                   ch := lst[i][1];
                   op2 := StrToFloat(lst[i-1]);
                   op1 := StrToFloat(lst[i-2]);
                   rez := SimplCalc(op1,op2,ch);
                   sRez := FloatToStr(rez);

                   // Убиваем теперь эти данные
                   for j:=i downto i-2 do
                       lst.Delete(j);
                   lst.Insert(i-2,sRez);
               end;
       end;
       result := StrToFloat(lst[0]);
finally
  lst.Free;
end;
end;


 
BorisMor ©   (2006-09-16 21:16) [8]

и продолжение...


////////////////////////////////////////////////////////////////////////////////
// Результат работы Postfix в виде строки
function PostfixStr(value: string): string;
var
lst: TStringList;
i: integer;
begin
result := "";
lst := TStringList.Create;
try
   Postfix(value, lst);
   for i:=0 to lst.Count-1 do
       result := result + lst[i]
finally
   lst.Free;
end;

end;
////////////////////////////////////////////////////////////////////////////////
// Копирует из lsIn в lsOut данные под номером ind (строку и Objects)
procedure CopyLine(lsSource,lsOut: TStringList; ind: integer);
var
i: integer;
s: string;
begin
if (ind > lsSource.Count-1) then exit;
s := lsSource[ind];
i := lsOut.Add(s);
lsOut.Objects[i] := lsSource.Objects[ind];
end;
////////////////////////////////////////////////////////////////////////////////
// Вовзращает приоритет операции
function PriorityOper(ch: char): integer;
begin
result := -1;
if (ch="+") or (ch="-") then result := 0 else
if (ch="*") or (ch="/") or (ch="\") then result := 1 else
end;
////////////////////////////////////////////////////////////////////////////////
// Сравнение операций. если сзначение newOp больше oldOp то возвращается true  
function CmpOper(newOp, oldOp: char): boolean;
var
iNew, iOld: integer;
begin
iNew := PriorityOper(newOp);
iOld := PriorityOper(oldOp);
result := iNew > iOld;
end;
////////////////////////////////////////////////////////////////////////////////
{ Вовзращает тип символа
tcNum - цифра
tcMath - математическая операциия
tcOScob - скобка открывается
tcCScob - скобка закрывается
tcOther - другое }
function TypeChar(c: Char): TTypeChar;
var
bChar: Byte;
begin
result := tcOther;
bChar := ord(c);
case bChar of
   $2A,$2B: result := tcMath; // мат. операции *+
   $2C: result := tcNum; // число ,
   $2D: result := tcMath; // мат. операции -
   $2E: result := tcNum; // число .
   $2F: result := tcMath; // мат. операции -
   $30..$39: result := tcNum; // числа
   $28: result := tcOScob; // (
   $29: result := tcCScob; // )
end;
end;
////////////////////////////////////////////////////////////////////////////////
// Разьивает строку value на лексеммы и помещает их в список
procedure BreakLex(value: string; ListLex: TStringList);
var
s,s1: string;
ch: Char;
sValue: string;
bChar: byte;
i,j,k: integer;
curType, newType: TTypeChar;
cutLex: string;
begin
ListLex.Clear;
if value = "" then exit;

// Убиваем не нужные символлы оставляем тольк: цыфры, зпт, тчк, и мат символлы
sValue := "";
j := length(value);
i := 1;
repeat
  ch := value[i];
  // Меняем пару символов ---
  if ch = "," then ch:="." else
  if ch = "\" then ch:="/";
  // ------------------------
  bChar := Ord(ch);

  if (bChar > $27) and ( bChar < $3A) then
       sValue := sValue + ch;
  inc(i);
until
   i > j;

j := length(sValue);
if j=0 then exit;

curType := tcOther;
cutLex := "";
i := 1;
inc(j);

// Сама разбивка на лексеммы
while i <= j do
   begin
     newType := TypeChar(sValue[i]);
     if (newType <> curType) then // началась новая лексемма
        begin
             if cutLex <> "" then
                 begin
                     k := ListLex.Add(cutLex);
                     ListLex.Objects[k] := Pointer(curType);
                     cutLex := "";
                 end; {if}
             curType := newType;
        end; {if}
     cutLex := cutLex + sValue[i];
     inc(i);
   end;

end;
////////////////////////////////////////////////////////////////////////////////
// Перевести в постфиксную форму
// Значени заносится в lsOut  
procedure Postfix(value: string; lsOut: TStringList);
var
lex, stack: TStringList;
i, top: integer;
sLex: string;
tLex: TTypeChar;
begin
lsOut.Clear;
lex := TStringList.Create;
stack := TStringList.Create;
try
   BreakLex(value,lex); // Разбили на лексеммы
   for i := 0 to lex.Count-1 do // проходимся по спику лексем
       begin
           sLex := lex[i]; // лексема
           tLex := TTypeChar(lex.Objects[i]); // что за лексема

           case tLex of
                 tcNum : CopyLine(lex,lsOut,i); // цыфры
               tcOScob : CopyLine(lex,stack,i); // Скобка открыта
               tcCScob : begin  // Скобка закрыта ==> берем данные из стека
                           top := stack.Count-1;
                           while (top > -1) and (stack[top] <> "(") do
                               begin
                                 CopyLine(stack,lsOut,top); // Копируем из стека top
                                 stack.Delete(top);
                                 dec(top);
                               end; {while}
                           if stack[top] = "(" then stack.Delete(top);
                         end;
               tcMath : // Математическая операция
                         begin
                           top := stack.Count-1;
                           if top < 0 then  // в  стеке нет числе ==> Заносим операцию в стек
                               CopyLine(lex,stack,i) // цыфры
                           else // В стеке есть данные
                               begin
                                 if CmpOper(sLex[1], stack[top][1]) then // приоритет новой операции >= чем в стеке ==> заносим в стек
                                    CopyLine(lex,stack,i)
                                 else
                                   begin
                                     while (top > -1) and (stack[top] <> "(") do //  Скидываем то что былов стеке
                                         begin
                                           CopyLine(stack,lsOut,top); // Копируем из стека top
                                           stack.Delete(top);
                                           dec(top);
                                         end; {wile}
                                     CopyLine(lex,stack,i); // цыфры
                                   end; {else}
                               end; {else}
                         end;
           end; {case}
       end; {for}

       // Выкладываем все что осталось в стеке
       top := stack.Count-1;
       while (top > -1) do
           begin
             CopyLine(stack,lsOut,top); // Копируем из стека top
             stack.Delete(top);
             dec(top);
           end;

finally
   stack.Free;
   lex.Free;
end;
end;
////////////////////////////////////////////////////////////////////////////////
end.


 
BorisMor ©   (2006-09-16 21:18) [9]

Блин... орфография в коментах конечно хромает :)


 
TUser ©   (2006-09-17 10:00) [10]

Алгоритм Дейкстры для перевода в обратную польскую запись - автору в зубы


 
Kerk ©   (2006-09-17 12:27) [11]

http://kladovka.net.ru



Страницы: 1 вся ветка

Текущий архив: 2006.10.08;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.069 c
15-1158060195
Real
2006-09-12 15:23
2006.10.08
Реален ли CMP - Crimea Mastak Party?


2-1159092333
Серый
2006-09-24 14:05
2006.10.08
Операция div


2-1158835939
evgenij_
2006-09-21 14:52
2006.10.08
RAVE REPORT


3-1154688564
Rentgen
2006-08-04 14:49
2006.10.08
INSERT в базе со счетчиком, возможно??


15-1158487787
ArtemESC
2006-09-17 14:09
2006.10.08
Полином