代码之家  ›  专栏  ›  技术社区  ›  ae.

用php处理数学方程

  •  8
  • ae.  · 技术社区  · 14 年前

    允许用户输入他们喜欢的任何数学公式(带一个变量):

    x + 5

    1 - x/2

    (x/3) * (56/13)

    我怎么能这样做?

    我正在考虑编写一个解析器来解构字符串并将其转换为方程式,但是这听起来很昂贵而且有问题。另一个选择是通过eval(但如果我能帮上忙的话,我不太喜欢使用eval)。

    有什么想法吗?

    我还需要能够得到像“(x>5)”这样的布尔值。这对evalMath来说是不可能的

    更新2: 我要开枪了 一秒钟。我一直在研究php中的eval,但无法让它返回布尔值(5>4),但我注意到js会这样做。。。也许我应该调查node.js。。。

    更新3: 在尝试node.js(并让它工作)之后,我回去让eval在PHP中工作参见: Can php eval return a boolean value?

    所以我将使用eval,它在用户输入上有一个非常核心的过滤器。

    8 回复  |  直到 7 年前
        1
  •  5
  •   symcbean    14 年前

    Eval不是邪恶的!!!!!

    是的,如果你写了错误的代码,它会让你的系统完全崩溃,但是最新的PHP版本可以解析一个无效的表达式,而不会导致整个脚本崩溃。还有很多其他方法可以通过编写错误代码来公开系统。

    这只会留下代码注入攻击的可能性——这很容易通过对不是安全字符的所有字符(即0….9,(,),+,-,*,/,^,)进行preg_替换来避免

        2
  •  12
  •   Mark Baker    14 年前

    我对这个问题的标准答案是:

    看看 evalMath 关于phpClass的类。它应该做你在这里列出的所有事情。

    编辑

    回复:很遗憾evalMath不能处理(x>5)这样的事情

    将第177-179行更改为

    $ops   = array('+', '-', '*', '/', '^', '_', '>', '<', '=');
    $ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>0, '>' => 0, '<' => 0, '=' => 0); // right-associative operator?
    $ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2, '>' => 0, '<' => 0, '=' => 0); // operator precedence
    

    将第184行更改为

    if (preg_match("/[^\w\s+*^\/()\.,-<>=]/", $expr, $matches)) { // make sure the characters are all good
    

    case '>':
         $stack->push($op1 > $op2); break;
    case '<':
         $stack->push($op1 < $op2); break;
    case '=':
         $stack->push($op1 == $op2); break;
    

    321线后

    evalMath现在将处理(x>5),(x<5)或(x=5)

    // instantiate a new EvalMath
    $m = new EvalMath;
    $m->suppress_errors = true;
    // set the value of x
    $m->evaluate('x = 3');
    var_dump($m->evaluate('y = (x > 5)'));
    

    第307行遗漏,应修改为:

    if (in_array($token, array('+', '-', '*', '/', '^', '>', '<', '='))) {
    
        3
  •  1
  •   Mike C    14 年前

    1 - x/2
    

    变成

    Array
    (
        [0] => -
        [1] => 1
        [2] => Array
            (
                [0] => /
                [1] => x
                [2] => 2
            )
    )
    

    编写解析器有点困难,但是计算解析后的公式非常容易。

        4
  •  1
  •   jellyfishtree    14 年前

    如果在linux机器上运行代码,有一点风险的可能性是使用bc命令(确保在将输入提供给system cmd之前正确地转义)。我不能说使用系统比eval的风险要好得多,所以我在这里期待一些否决票。

        5
  •  0
  •   tanjir    14 年前

    即使你通过了eval,你也必须用一些数字来代替x。我需要的策略是传递x的值,然后看看被评估的值是多少。如果大于0,则尝试较小的数字;如果小于0,则递归尝试较大的数字,直到它满足错误边距(<>0.001%)。

        6
  •  0
  •   Davis Peixoto    14 年前

    取决于。。。

    它将接受什么样的复杂性?因为对于常见的数学公式(如您所发布的),我认为编写解析器没有太多问题。主要有问题的问题是将数字舍入并放上正确的括号。

    但是,如果方程要接受“高级”输入,比如{[……]},或者X,X,或者更进一步,微分学和大学数学,那么事情可能会变得疯狂。

    当然,我强烈建议您为输入创建自己的系统,对其进行验证,并鼓励用户将输入与它联系起来。没什么太复杂的,但足以让你(和其他人)感到舒适和安全,达到你所需要的。

        7
  •  -1
  •   Cesar    14 年前

    评估()

    取决于您必须做什么,但无论如何,最便宜的方法是对变量使用replace函数,然后使用eval()运行表达式。
    当然,您首先需要确保您的公式使用php语法。

    PHP类


    http://www.phpclasses.org/package/2695-PHP-Safely-evaluate-mathematical-expressions.html

        8
  •  -1
  •   Marcodor    7 年前

    使用 eval

    尝试 Matex