Как математически оценить строку типа «2-1» для создания «1»?

Мне просто интересно, есть ли у PHP функция, которая может взять строку вроде 2-1 и получить арифметический результат?

Или мне нужно сделать это вручную с помощью explode() чтобы получить значения слева и справа от арифметического оператора?

Я знаю, что этот вопрос старый, но я наткнулся на него прошлой ночью, ища что-то, что не совсем связано, и каждый ответ здесь плохой. Не просто плохо, очень плохо. Примеры, которые я приведу здесь, будут из класса, который я создал еще в 2005 году, и потратил последние несколько часов на обновление PHP5 из-за этого вопроса. Другие системы существуют и были вокруг, прежде чем этот вопрос был отправлен, поэтому он меня озадачивает, почему каждый ответ здесь говорит вам использовать eval , когда предостережение от PHP:

Конструкция языка eval () очень опасна, поскольку позволяет выполнять произвольный PHP-код. Поэтому его использование не рекомендуется. Если вы тщательно проверили, что нет другого выбора, кроме использования этой конструкции, обратите особое внимание на то, чтобы не передавать какие-либо данные, предоставленные пользователем, без предварительной проверки.

Прежде чем я перейду к примеру, места для получения класса I будут использоваться либо в PHPClasses, либо в GitHub . Оба eos.class.php и stack.class.php необходимы, но могут быть объединены в один и тот же файл.

Причина использования такого класса заключается в том, что он включает в себя и инфикс для postfix (RPN) парсер, а затем RPN Solver. При этом вам никогда не придется использовать функцию eval и открывать вашу систему до уязвимостей. Когда у вас есть классы, следующий код – это все, что необходимо для решения простого (более сложного) уравнения, такого как ваш пример 2-1 .

 require_once "eos.class.php"; $equation = "2-1"; $eq = new eqEOS(); $result = $eq->solveIF($equation); 

Это оно! Вы можете использовать синтаксический анализатор, подобный этому, для большинства уравнений, как бы они ни были сложными и вложенными, без необходимости прибегать к «злой eval ».

Потому что я действительно не хочу, чтобы это имело только мой класс, вот некоторые другие варианты. Я просто знаком с моим собственным, так как я использую его в течение 8 лет. ^^

Wolfram | Alpha API
шалфей
Довольно плохой парсер
phpdicecalc

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

В любом случае, я хотел убедиться, что ответ на решение уравнений в PHP здесь не указывает на то, что все будущие искатели будут eval поскольку это было в верхней части поиска Google. ^^

 $operation='2-1'; eval("\$value = \"$operation\";"); 

или

 $value=eval("return ($op);"); 

Это один из случаев, когда eval пригодится:

 $expression = '2 - 1'; eval( '$result = (' . $expression . ');' ); echo $result; 

Вы можете использовать произвольную точность BC Math

 echo bcsub(5, 4); // 1 echo bcsub(1.234, 5); // 3 echo bcsub(1.234, 5, 4); // -3.7660 

http://www.php.net/manual/en/function.bcsub.php

На этом форуме кто-то сделал это без eval . Может быть, вы можете попробовать? Кредиты им, я только что нашел.

 function calculate_string( $mathString ) { $mathString = trim($mathString); // trim white spaces $mathString = ereg_replace ('[^0-9\+-\*\/\(\) ]', '', $mathString); // remove any non-numbers chars; exception for math operators $compute = create_function("", "return (" . $mathString . ");" ); return 0 + $compute(); } $string = " (1 + 1) * (2 + 2)"; echo calculate_string($string); // outputs 8 

Также см. Этот ответ здесь: Оценка строки простых математических выражений

Обратите внимание, что это решение НЕ соответствует BODMAS, но вы можете использовать скобки в своей оценочной строке, чтобы преодолеть это.

 function callback1($m) { return string_to_math($m[1]); } function callback2($n,$m) { $o=$m[0]; $m[0]=' '; return $o=='+' ? $n+$m : ($o=='-' ? $n-$m : ($o=='*' ? $n*$m : $n/$m)); } function string_to_math($s){ while ($s != ($t = preg_replace_callback('/\(([^()]*)\)/','callback1',$s))) $s=$t; preg_match_all('![-+/*].*?[\d.]+!', "+$s", $m); return array_reduce($m[0], 'callback2'); } echo string_to_match('2-1'); //returns 1 

Вот несколько подробный бит кода, который я закатил для другого вопроса SO . Он соответствует BO MDAS без eval() , но не предназначен для выполнения сложных / высших порядков / скобок. Этот метод, свободный от библиотеки, вытягивает выражение отдельно и систематически уменьшает массив компонентов до тех пор, пока все операторы не будут удалены. Это, безусловно, работает для вашего образца: 2-1 😉

  1. preg_match() проверяет, что каждый оператор имеет числовую подстроку с каждой стороны.
  2. preg_split() делит строку на массив переменных чисел и операторов.
  3. array_search() находит индекс целевого оператора, тогда как он существует в массиве.
  4. array_splice() заменяет операторский элемент и элементы по обе стороны от него новым элементом, который содержит математический результат трех удаленных элементов.

** обновлено, чтобы дать отрицательные номера **

Код: ( Демо )

 $expression="-11+3*1*4/-6-12"; if(!preg_match('~^-?\d*\.?\d+([*/+-]-?\d*\.?\d+)*$~',$expression)){ echo "invalid expression"; }else{ $components=preg_split('~(?<=\d)([*/+-])~',$expression,NULL,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); var_export($components); // ['-11','+','3','*','1','*','4','/','-6','-','12'] while(($index=array_search('*',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]*$components[$index+1]); var_export($components); // ['-11','+','3','*','4','/','-6','-','12'] // ['-11','+','12','/','-6','-','12'] } while(($index=array_search('/',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]/$components[$index+1]); var_export($components); // [-'11','+','-2','-','12'] } while(($index=array_search('+',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]+$components[$index+1]); var_export($components); // ['-13','-','12'] } while(($index=array_search('-',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]-$components[$index+1]); var_export($components); // [-25] } echo current($components); // -25 } в $expression="-11+3*1*4/-6-12"; if(!preg_match('~^-?\d*\.?\d+([*/+-]-?\d*\.?\d+)*$~',$expression)){ echo "invalid expression"; }else{ $components=preg_split('~(?<=\d)([*/+-])~',$expression,NULL,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); var_export($components); // ['-11','+','3','*','1','*','4','/','-6','-','12'] while(($index=array_search('*',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]*$components[$index+1]); var_export($components); // ['-11','+','3','*','4','/','-6','-','12'] // ['-11','+','12','/','-6','-','12'] } while(($index=array_search('/',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]/$components[$index+1]); var_export($components); // [-'11','+','-2','-','12'] } while(($index=array_search('+',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]+$components[$index+1]); var_export($components); // ['-13','-','12'] } while(($index=array_search('-',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]-$components[$index+1]); var_export($components); // [-25] } echo current($components); // -25 } в $expression="-11+3*1*4/-6-12"; if(!preg_match('~^-?\d*\.?\d+([*/+-]-?\d*\.?\d+)*$~',$expression)){ echo "invalid expression"; }else{ $components=preg_split('~(?<=\d)([*/+-])~',$expression,NULL,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); var_export($components); // ['-11','+','3','*','1','*','4','/','-6','-','12'] while(($index=array_search('*',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]*$components[$index+1]); var_export($components); // ['-11','+','3','*','4','/','-6','-','12'] // ['-11','+','12','/','-6','-','12'] } while(($index=array_search('/',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]/$components[$index+1]); var_export($components); // [-'11','+','-2','-','12'] } while(($index=array_search('+',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]+$components[$index+1]); var_export($components); // ['-13','-','12'] } while(($index=array_search('-',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]-$components[$index+1]); var_export($components); // [-25] } echo current($components); // -25 } в $expression="-11+3*1*4/-6-12"; if(!preg_match('~^-?\d*\.?\d+([*/+-]-?\d*\.?\d+)*$~',$expression)){ echo "invalid expression"; }else{ $components=preg_split('~(?<=\d)([*/+-])~',$expression,NULL,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); var_export($components); // ['-11','+','3','*','1','*','4','/','-6','-','12'] while(($index=array_search('*',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]*$components[$index+1]); var_export($components); // ['-11','+','3','*','4','/','-6','-','12'] // ['-11','+','12','/','-6','-','12'] } while(($index=array_search('/',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]/$components[$index+1]); var_export($components); // [-'11','+','-2','-','12'] } while(($index=array_search('+',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]+$components[$index+1]); var_export($components); // ['-13','-','12'] } while(($index=array_search('-',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]-$components[$index+1]); var_export($components); // [-25] } echo current($components); // -25 } в $expression="-11+3*1*4/-6-12"; if(!preg_match('~^-?\d*\.?\d+([*/+-]-?\d*\.?\d+)*$~',$expression)){ echo "invalid expression"; }else{ $components=preg_split('~(?<=\d)([*/+-])~',$expression,NULL,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); var_export($components); // ['-11','+','3','*','1','*','4','/','-6','-','12'] while(($index=array_search('*',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]*$components[$index+1]); var_export($components); // ['-11','+','3','*','4','/','-6','-','12'] // ['-11','+','12','/','-6','-','12'] } while(($index=array_search('/',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]/$components[$index+1]); var_export($components); // [-'11','+','-2','-','12'] } while(($index=array_search('+',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]+$components[$index+1]); var_export($components); // ['-13','-','12'] } while(($index=array_search('-',$components))!==false){ array_splice($components,$index-1,3,$components[$index-1]-$components[$index+1]); var_export($components); // [-25] } echo current($components); // -25 } 

Вот демонстрация версии B OMDAS, которая использует php's pow() когда ^ встречается между двумя номерами (положительными или отрицательными).

Я не думаю, что когда-нибудь буду писать версию, которая обрабатывает скобки … но мы увидим, как мне скучно.