Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Я знаю, что этот вопрос старый, но я наткнулся на него прошлой ночью, когда искал что-то, что было не совсем связано, и каждый ответ здесь плохой. Не просто плохо, очень плохо. Примеры, которые я приведу здесь, будут из класса, который я создал еще в 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. ^^

Ответ 2

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

или

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

Ответ 3

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

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

Ответ 4

Вы можете использовать произвольную точность 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

Ответ 5

В этот форум кто-то сделал это без 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  

Ответ 6

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

Обратите внимание, что это решение НЕ соответствует 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

Ответ 7

Вот несколько подробный бит кода, который я закатил для другого вопроса 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(), когда ^ встречается между двумя числами (положительными или отрицательными).

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