web-dev-qa-db-ja.com

evalを使用して文字列から数式を計算する

文字列から数式を計算したい。これに対する解決策は、eval()を使用することです。しかし、次のコードを実行しようとすると:

<?php

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

?>

次のエラーが表示されます。

解析エラー:構文エラー、C:\ xampp\htdocs\eclipseWorkspaceWebDev\MandatoryHandinSite\tester.php(4)の予期しない$ end:1行目のeval() 'dコード

誰かがこの問題の解決策を知っていますか。

20
Langkiller

このためにevalを使用することはお勧めしませんが(解決策はnotです)、問題は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;
}
46
Rocket Hazmat

これをみて..

これは、金額入力フィールドに数式を記​​述できる会計システムで使用します。

$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]);
            }
            // 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.';');

        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;
    }
}
29
clarkk

文字列引数を制御できない場合、 eval 関数を使用することは非常に危険です。

安全な数式計算のために Matex を試してください。

1
Marcodor

最近、PHPパッケージを作成し、math_evalヘルパー関数。潜在的に安全ではないeval関数を使用することなく、まさに必要なことを行います。

数式の文字列バージョンを渡すだけで、結果が返されます。

$two   = math_eval('1 + 1');
$three = math_eval('5 - 2');
$ten   = math_eval('2 * 5');
$four  = math_eval('8 / 2');

必要に応じて置換される変数を渡すこともできます。

$ten     = math_eval('a + b', ['a' => 7, 'b' => 3]);
$fifteen = math_eval('x * y', ['x' => 3, 'y' => 5]);

リンク: https://github.com/langleyfoxall/math_eval

1
DivineOmega

eval指定されたコードをPHPとして評価します。つまり、指定されたパラメーターをPHPコードの一部として実行します。

コードを修正するには、これを使用します:

$ma ="print (2+10);";
eval($ma);
0
S.Thiongane

Eval関数を使用する

 protected function getStringArthmeticOperation($value, $deduct)
{
    if($value > 0){
        $operator = '-';
    }else{
        $operator = '+';
    }
    $mathStr = '$value $operator $deduct';
    eval("\$mathStr = \"$mathStr\";");
    $userAvailableUl = eval('return '.$mathStr.';');
    return $userAvailableUl;
}

$this->getStringArthmeticOperation(3, 1); //2
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

この方法には2つの大きな欠点があります。

  • セキュリティ、phpスクリプトはeval関数によって評価されています。これは、特にユーザーが悪意のあるコードを挿入したい場合によくありません。

  • 複雑

これを作成したので、チェックしてみてください: Formula Interpreter

どのように機能しますか?

最初に、式とそのパラメーターを使用してFormulaInterpreterのインスタンスを作成します

_$formulaInterpreter = new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]);
_

execute()メソッドを使用して、式を解釈します。結果を返します:

_echo $formulaInterpreter->execute();
_

一行で

_echo (new FormulaInterpreter("x + y", ["x" => 10, "y" => 20]))->execute();
_

_# Formula: speed = distance / time
$speed = (new FormulaInterpreter("distance/time", ["distance" => 338, "time" => 5]))->execute() ;
echo $speed;


#Venezuela night overtime (ordinary_work_day in hours): (normal_salary * days_in_a_work_month)/ordinary_work_day
$parameters = ["normal_salary" => 21000, "days_in_a_work_month" => 30, "ordinary_work_day" => 8];
$venezuelaLOTTTArt118NightOvertime = (new FormulaInterpreter("(normal_salary/days_in_a_work_month)/ordinary_work_day", $parameters))->execute();
echo $venezuelaLOTTTArt118NightOvertime;


#cicle area
$cicleArea = (new FormulaInterpreter("3.1416*(radio*radio)", ["radio" => 10]))->execute();
echo $cicleArea;

_

数式について

  1. 少なくとも2つのオペランドと1つの演算子が含まれている必要があります。
  2. オペランドの名前は大文字でも小文字でもかまいません。
  3. 現在、sin、cos、pow…などの数学関数は含まれていません。私はそれらを含めるように取り組んでいます。
  4. 数式が無効な場合、次のようなエラーメッセージが表示されます:エラー、数式(single_variable)は無効です。
  5. パラメーターの値は数値でなければなりません。

必要に応じて改善できます!

0
Carlos Espinoza