如何math评估像“2-1”的string来产生“1”?

我只是想知道如果PHP有一个function,可以采取像2-1的string,并产生它的算术结果?

或者我将不得不使用explode()手动执行此操作以获取算术运算符左侧和右侧的值?

我知道这个问题很老,但是我昨晚在search一些不太相关的东西的时候遇到了这个问题,这里的每一个答案都是不好的。 不仅坏, 非常糟糕。 我在这里给出的例子将来自我在2005年创build的一个类,因为这个问题花了几个小时更新PHP5。 其他系统确实存在,并且在这个问题发布之前就已经存在了,所以它让我感到困惑,为什么在这里的每个答案都告诉你使用eval ,当时PHP的警告是:

eval()语言结构非常危险,因为它允许执行任意的PHP代码。 因此,它的使用是不鼓励的。 如果您已经仔细核实没有其他select使用此构造,请特别注意不要将任何用户提供的数据传递给它,而无需事先进行适当的validation。

在进入这个例子之前,我将要使用的地方是PHPClasses或者GitHub 。 eos.class.phpstack.class.php都是必需的,但可以合并到同一个文件中。

使用这样一个类的原因是它包含并附加到后缀(RPN)分析器,然后RPN求解器。 有了这些,你永远不必使用eval函数,并打开你的系统的漏洞。 一旦你有了这些类,下面的代码就可以解决一个简单的(到更复杂的)方程,比如你的2-1例子。

 require_once "eos.class.php"; $equation = "2-1"; $eq = new eqEOS(); $result = $eq->solveIF($equation); 

而已! 对于大多数方程式,您可以使用这样的parsing器,但无需使用“邪恶eval ”即可复杂和嵌套。

因为我真的不希望这只是为了让我的class级,这里有一些其他的select。 自从我使用了8年以来,我就已经熟悉了我自己。 ^^

Wolfram | Alpha API
智者
一个相当糟糕的parsing器
phpdicecalc

不太清楚之前发现的其他人发生了什么 – 之前在GitHub上也遇到过另外一个,不幸的是我没有将它join书签,但是它涉及到包含parsing器的大型浮动操作。

无论如何,我想确定一个PHP解决scheme的答案在这里没有指出所有未来的search者评价,因为这是在谷歌search的顶部。 ^^

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

要么

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

这是eval派上用场的一个例子:

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

您可以使用BCmath任意精度

 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

在这个论坛有人没有评价。 也许你可以试试吗? 学分给他们,我刚刚find了。

 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 

在这里也可以看到这个答案: 评估一串简单的mathexpression式

请注意,此解决scheme不符合BODMAS,但您可以在评估string中使用括号来克服此问题。

 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 

这里有一些我详细讨论的问题 。 它不符合BO MDAS没有eval() ,但没有装备做复杂/高阶/括号expression式。 这种无库方法将expression式拉开,系统地减less了组件的数组,直到所有的操作符被删除。 它当然适用于你的示例expression式: 2-1 ;)

  1. preg_match()检查每个运算符在每一边都有一个数字子string。
  2. preg_split()将string分为交替数字和运算符的数组。
  3. array_search()在存在于数组中的情况下查找目标运算符的索引。
  4. array_splice()用一个新的元素来replace运算符元素和它的任一侧的元素,这个新的元素包含被删除的三个元素的math结果。

**更新为允许负数**

代码:( 演示 )

 $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() (正数或负数)。

我不认为我会永远不会写一个处理括号expression的版本…但是我们会看到我得到多么无聊。