2013-09-18 4 views
15

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

<?php 

$ma ="2+10"; 
$p = eval($ma); 
print $p; 

?> 

Это дает мне следующее сообщение об ошибке:

Parse error: syntax error, unexpected $end in C:\xampp\htdocs\eclipseWorkspaceWebDev\MandatoryHandinSite\tester.php(4) : eval()'d code on line 1

Кто-то знает решение этой проблемы.

+2

Вы можете взломать что-то с помощью 'eval()', но никто никогда не должен использовать eval для чего-либо * когда-либо *. [Проверить это решение] (http://stackoverflow.com/a/1015281/1064767). – Sammitch

+0

ладно спасибо .. что плохого в использовании eval(), если я могу спросить? – Langkiller

+0

@ user68621: It * очень * небезопасный. Откуда взялась строка '$ ma'? Вход пользователя? Что, если я отправил 'rmdir ('/ var/www');' или что-то в качестве моего ввода? –

ответ

28

Пока я не предлагаю использовать eval для этого (это не решение), проблема заключается в том, что eval ожидает полные строки кода, а не только фрагменты.

$ma ="2+10"; 
$p = eval('return '.$ma.';'); 
print $p; 

Должен делать то, что вы хотите.


Лучшим решением было бы написать токенизатор/парсер для вашего математического выражения. Вот очень простой регулярное выражение на основе один, чтобы дать вам пример:

$ma = "2+10"; 

if(preg_match('/(\d+)(?:\s*)([\+\-\*\/])(?:\s*)(\d+)/', $ma, $matches) !== FALSE){ 
    $operator = $matches[2]; 

    switch($operator){ 
     case '+': 
      $p = $matches[1] + $matches[3]; 
      break; 
     case '-': 
      $p = $matches[1] - $matches[3]; 
      break; 
     case '*': 
      $p = $matches[1] * $matches[3]; 
      break; 
     case '/': 
      $p = $matches[1]/$matches[3]; 
      break; 
    } 

    echo $p; 
} 
+0

Я добавил предложение для лучшего решения. Это не самое большое, но я надеюсь, что это дает представление о том, что вам нужно делать. Я уверен, что вы можете использовать Google для лучшего решения. –

+1

Это действительно хорошо, за исключением моей функции, где у меня есть 24,5 * 12, она занимает первое число как 5 вместо 24,5, так как она выглядит исключительно для цифр –

+1

Замена шаблона следующим образом сделала трюк для меня (позволяет цифры, пробелы , и десятичное число) - обратите внимание, что он будет соответствовать номерам с пробелами в них (например, «201.5 + 11 2012 = 212,5», поэтому математика не будет работать корректно, не снимая эти пробелы (через 'str_replace' around' $ matches [1] 'и' $ matches [3] 'или аналогичные). Это будет полностью зависеть от вашего использования - это сработало для моих нужд.' /([\d\.\s]+)([\+\- \ * \ /]) ([\ d \. \ s] +)/' –

0

eval Оценивает данный код в PHP. Это означает, что он выполнит данный параметр как часть кода PHP.

Чтобы исправить код, используйте:

$ma ="print (2+10);"; 
eval($ma); 
-2

Эвальд выражение должно заканчиваться ";"

Попробуйте это:

$ma ="2+10;"; 
$p = eval($ma); 
print $p; 

Кстати, это выходит за рамки, но функция «Eval» не будет возвращать значение выражения. eval ('2 + 10') не вернется 12. Если вы хотите, чтобы он вернул 12, вы должны eval ('return 2 + 10;');

+0

, который покажет пустую страницу, потому что переменная '$ p' пуста. добавьте 'echo' внутрь:' $ ma = "echo 2 + 10;"; ' –

+0

@mansoulx. Это именно то, что было сказано в ответе выше ('return 2 + 10'). – ibtarek

20

Взгляните на это ..

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

Примеры

$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 

Код
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]); 
      } 

      return 0; 
     } 

     return $input; 
    } 

    private function compute($input){ 
     $compute = create_function('', '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; 
    } 
} 
+0

Ваш класс очень полезен! Спасибо! Но можете ли вы расширить свой класс, чтобы «(5 + 2)» не возвращал 0? – Flo

+0

он может решить 13/18-1/2 х 40, 13/18 х 40, 14 3/16/21 х 40, 16 3/16/23 х 40, 16-3/16/30 х 60, 9.75 х 21.5/29.5, 1/4 х 5, 1/2 х 6, 7 х 60, 8 Ga. х 4, 22 х 36, 35/64 х 6 –

+0

я написал короткий тест для ваших выражений @PushpendraSingh Если он соответствует вашим требованиям (например, обнаружение пробелов, верхний регистр x и т. д.) зависит от вас. https://gist.github.com/DBX12/2e1d622a0fa0937874ac3cf5eeecef51 – DBX12

0

Решенный!

<?php 
function evalmath($equation) 
{ 
    $result = 0; 
    // sanitize imput 
    $equation = preg_replace("/[^a-z0-9+\-.*\/()%]/","",$equation); 
    // convert alphabet to $variabel 
    $equation = preg_replace("/([a-z])+/i", "\$$0", $equation); 
    // convert percentages to decimal 
    $equation = preg_replace("/([+-])([0-9]{1})(%)/","*(1\$1.0\$2)",$equation); 
    $equation = preg_replace("/([+-])([0-9]+)(%)/","*(1\$1.\$2)",$equation); 
    $equation = preg_replace("/([0-9]{1})(%)/",".0\$1",$equation); 
    $equation = preg_replace("/([0-9]+)(%)/",".\$1",$equation); 
    if ($equation != ""){ 
     $result = @eval("return " . $equation . ";"); 
    } 
    if ($result == null) { 
     throw new Exception("Unable to calculate equation"); 
    } 
    echo $result; 
    // return $equation; 
} 


$a = 2; 
$b = 3; 
$c = 5; 
$f1 = "a*b+c"; 

$f1 = str_replace("a", $a, $f1); 
$f1 = str_replace("b", $b, $f1); 
$f1 = str_replace("c", $c, $f1); 

evalmath($f1); 
/*if ($equation != ""){ 

    $result = @eval("return " . $equation . ";"); 
} 
if ($result == null) { 

    throw new Exception("Unable to calculate equation"); 
} 
echo $result;*/ 
?> 
0

Использование функции eval очень опасно, если вы не можете управлять аргументом строки.

Попробуйте Matex для безопасного расчета математических формул.

+0

Какой стандарт вы использовали для обозначения ваших переменных и методов с прописными буквами? Это не условно. Дружественный совет - измените общий стандарт, если вы хотите, чтобы другие люди использовали вашу библиотеку. –

+0

@ AlexCalm1Kov, oki, попытается приспособиться к верблюду, однако мне это не нравится. В настоящее время он совместим с PSR, поэтому должен работать с автопогрузчиками. – Marcodor

Смежные вопросы