Мне просто интересно, имеет ли PHP функцию, которая может взять строку типа 2-1
и получить арифметический результат?
Или мне нужно сделать это вручную с помощью explode()
, чтобы получить значения слева и справа от арифметического оператора?
Мне просто интересно, имеет ли PHP функцию, которая может взять строку типа 2-1
и получить арифметический результат?
Или мне нужно сделать это вручную с помощью explode()
, чтобы получить значения слева и справа от арифметического оператора?
Я знаю, что этот вопрос старый, но я наткнулся на него прошлой ночью, когда искал что-то, что было не совсем связано, и каждый ответ здесь плохой. Не просто плохо, очень плохо. Примеры, которые я приведу здесь, будут из класса, который я создал еще в 2005 году, и потратил последние несколько часов на обновление PHP5 из-за этого вопроса. Другие системы существуют и были вокруг до того, как этот вопрос был опубликован, поэтому это меня озадачивает, почему каждый ответ здесь говорит вам использовать eval
, когда предостережение от PHP
Конструкция языка eval() очень опасна, поскольку позволяет выполнять произвольный PHP-код. Поэтому его использование не рекомендуется. Если вы тщательно проверили, что нет другого выбора, кроме использования этой конструкции, обратите особое внимание на то, чтобы не передавать какие-либо данные, предоставленные пользователем, без предварительной проверки.
Прежде чем перейти к примеру, места для получения класса, который я буду использовать, находятся на 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
Sage
Довольно плохой парсер
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
В этот форум кто-то сделал это без 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
;)
preg_match()
проверяет, что каждый оператор имеет числовую подстроку с каждой стороны.preg_split()
делит строку на массив переменных чисел и операторов.array_search()
находит индекс целевого оператора, в то время как он существует в массиве.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
}
Вот демонстрационная версия версии B OMDAS, которая использует php pow()
, когда ^
встречается между двумя числами (положительными или отрицательными).
Я не думаю, что когда-нибудь буду писать версию, которая обрабатывает скобки... но мы увидим, как мне скучно.