A
A
Anatoly2020-01-23 19:38:08
PHP
Anatoly, 2020-01-23 19:38:08

Are there solutions for mathematical calculations from a string?

Currently using:
https://stackoverflow.com/questions/18880772/calcu...
Usage:

``````\$Cal = new Field_calculate();

\$result = \$Cal->calculate('5+7'); // 12
\$result = \$Cal->calculate('(5+9)*5'); // 70
\$result = \$Cal->calculate('(10.2+0.5*(2-0.4))*2+(2.1*4)'); // 30.4``````

Code here
class Field_calculate {
const PATTERN = '/(?:\-?\d+(?:\.?\d+)?[\+\-\*\/])+\-?\d+(?:\.?\d+)?/';
const PARENTHESIS_DEPTH = 10;
public function calculate(\$input){
if(strpos(\$input, '+') != null || strpos(\$input, '-') != null || strpos(\$input, '/') != null || strpos(\$input, '*') != null){
// Remove white spaces and invalid math chars
\$input = str_replace(',', '.', \$input);
\$input = preg_replace('[^0-9\.\+\-\*\/\(\)]', '', \$input);
// Calculate each of the parenthesis from the top
\$i = 0;
while(strpos(\$input, '(') || strpos(\$input, ')')){
\$input = preg_replace_callback('/\(([^\(\)]+)\)/', 'self::callback', \$input);
\$i++;
if(\$i > self::PARENTHESIS_DEPTH) break;
}
// Calculate the result
if(preg_match(self::PATTERN, \$input, \$match)) return \$this->compute(\$match[0]);
// To handle the special case of expressions surrounded by global parenthesis like "(1+1)"
if(is_numeric(\$input)) return \$input;
return 0;
}
return \$input;
}
private function compute(\$input){
\$compute = create_function('', 'return '.\$input.';');
//\$compute = function(\$input){return \$input;}; попытка заменить create_function
//или убрать \$compute=.. а return заменить
//return 0 + eval('return '.\$input.';');
return 0 + \$compute();
}
private function callback(\$input){
if(is_numeric(\$input[1])) return \$input[1];
elseif(preg_match(self::PATTERN, \$input[1], \$match)) return \$this->compute(\$match[0]);
return 0;
}
}

But the problem is that using php7.3 I get an error that the function is deprecated:
Function `create_function()`is deprecated
Specifically, on the line from the code:
``\$compute = create_function('', 'return '.\$input.';');``

Tell me what to replace the code with to get rid of the error, or another solution.
PS. eval don't offer

A
Anatoly, 2020-01-23
@Tolly

Found a solution that worked for me:
https://ru.stackoverflow.com/questions/454598/%D0%...

the code
// Исключения для парсера выражений
class AriphmeticException extends Exception {
function __construct(\$msg, \$code) {
return parent::__construct(\$msg, \$code);
}
function __toString() {
return get_class(\$this) . '('
. \$this->code . '): '
. \$this->message;
}
}
// Собственно сам вычислитель выражений
function calculate(\$statement) {
if (!is_string(\$statement)) {
throw new AriphmeticException('Wrong type', 1);
}
\$calcQueue = array();
\$operStack = array();
\$operPriority = array(
'(' => 0,
')' => 0,
'+' => 1,
'-' => 1,
'*' => 2,
'/' => 2,
);
\$token = '';
foreach (str_split(\$statement) as \$char) {
// Если цифра, то собираем из цифр число
if (\$char >= '0' && \$char <= '9') {
\$token .= \$char;
} else {
// Если число накопилось, сохраняем в очереди вычисления
if (strlen(\$token)) {
array_push(\$calcQueue, \$token);
\$token = '';
}
// Если найденный символ - операция (он есть в списке приоритетов)
if (isset(\$operPriority[\$char])) {
if (')' == \$char) {
// Если символ - закрывающая скобка, переносим операции из стека в очередь вычисления пока не встретим открывающую скобку
while (!empty(\$operStack)) {
\$oper = array_pop(\$operStack);
if ('(' == \$oper) {
break;
}
array_push(\$calcQueue, \$oper);
}
if ('(' != \$oper) {
// Упс! А открывающей-то не было. Сильно ругаемся (18+)
throw new AriphmeticException('Unexpected ")"', 2);
}
} else {
// Встретили операцию кроме скобки. Переносим операции с меньшим приоритетом в очередь вычисления
while (!empty(\$operStack) && '(' != \$char) {
\$oper = array_pop(\$operStack);
if (\$operPriority[\$char] > \$operPriority[\$oper]) {
array_push(\$operStack, \$oper);
break;
}
if ('(' != \$oper) {
array_push(\$calcQueue, \$oper);
}
}
// Кладем операцию на стек операций
array_push(\$operStack, \$char);
}
} elseif (strpos(' ', \$char) !== FALSE) {
// Игнорируем пробелы (можно добавить что еще игнорируем)
} else {
// Встретили что-то непонятное (мы так не договаривались). Опять ругаемся
throw new AriphmeticException('Unexpected symbol "' . \$char . '"', 3);
}
}
}
// Вроде все разобрали, но если остались циферки добавляем их в очередь вычисления
if (strlen(\$token)) {
array_push(\$calcQueue, \$token);
\$token = '';
}
// ... и оставшиеся в стеке операции
if (!empty(\$operStack)) {
while (\$oper = array_pop(\$operStack)) {
if ('(' == \$oper) {
// ... кроме открывающих скобок. Это верный признак отсутствующей закрывающей
throw new AriphmeticException('Unexpected "("', 4);
}
array_push(\$calcQueue, \$oper);
}
}
\$calcStack = array();
// Теперь вычисляем все то, что напарсили
// Тут ошибки не ловил, но они могут быть (это домашнее задание)
foreach (\$calcQueue as \$token) {
switch (\$token) {
case '+':
\$arg2 = array_pop(\$calcStack);
\$arg1 = array_pop(\$calcStack);
array_push(\$calcStack, \$arg1 + \$arg2);
break;
case '-':
\$arg2 = array_pop(\$calcStack);
\$arg1 = array_pop(\$calcStack);
array_push(\$calcStack, \$arg1 - \$arg2);
break;
case '*':
\$arg2 = array_pop(\$calcStack);
\$arg1 = array_pop(\$calcStack);
array_push(\$calcStack, \$arg1 * \$arg2);
break;
case '/':
\$arg2 = array_pop(\$calcStack);
\$arg1 = array_pop(\$calcStack);
array_push(\$calcStack, \$arg1 / \$arg2);
break;
default:
array_push(\$calcStack, \$token);
}
}
return array_pop(\$calcStack);
}

A

Okay, google. We write a calculator in ... yes, at least in puff, what's the difference?

A
Alexander Aksentiev, 2020-01-23
@Sanasol

PS. eval don't offer

https://www.php.net/manual/ru/function.create-func...
Those. eval is embarrassing, but is create_function okay?)
And so parse and that's it.
The same question on SO has a solution below without eval
https://stackoverflow.com/a/53103580/1603055

Didn't find what you were looking for?