如何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.php
和stack.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
在这个论坛有人没有评价。 也许你可以试试吗? 学分给他们,我刚刚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
;)
-
preg_match()
检查每个运算符在每一边都有一个数字子string。 -
preg_split()
将string分为交替数字和运算符的数组。 -
array_search()
在存在于数组中的情况下查找目标运算符的索引。 -
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的版本…但是我们会看到我得到多么无聊。