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

Answer the question

In order to leave comments, you need to log in

3 answer(s)
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
Adamos, 2020-01-23
@Adamos

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?

Ask your question

Ask a Question

731 491 924 answers to any question