Php 如何从数学上计算字符串,如;2-1“;生产;“1”吗;?

Php 如何从数学上计算字符串,如;2-1“;生产;“1”吗;?,php,math,numbers,operators,eval,Php,Math,Numbers,Operators,Eval,我只是想知道PHP是否有一个函数可以接受像2-1这样的字符串并生成它的算术结果 或者我必须手动使用explode()来获取算术运算符的左右值吗 $operation='2-1'; eval("\$value = \"$operation\";"); 或 这是其中一种方便的情况: $expression = '2 - 1'; eval( '$result = (' . $expression . ');' ); echo $result; 您可以使用BC Math任意精度 echo bcsub

我只是想知道PHP是否有一个函数可以接受像
2-1
这样的字符串并生成它的算术结果

或者我必须手动使用
explode()
来获取算术运算符的左右值吗

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


这是其中一种方便的情况:

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

您可以使用BC Math任意精度

echo bcsub(5, 4); // 1
echo bcsub(1.234, 5); // 3
echo bcsub(1.234, 5, 4); // -3.7660

我知道这个问题很老,但我昨晚在寻找一些不太相关的东西时遇到了它,这里的每个答案都不好。不仅糟糕,非常糟糕。我在这里给出的例子来自我在2005年创建的一个类,由于这个问题,我在过去的几个小时里一直在更新PHP5。其他系统确实存在,并且在这个问题发布之前就已经存在,所以我很困惑为什么这里的每个答案都告诉您要使用,而PHP的警告是:

eval()语言构造非常危险,因为它允许执行任意PHP代码。因此,不鼓励使用它。如果您已经仔细验证了除了使用此构造之外没有其他选择,请特别注意,在未事先正确验证的情况下,不要将任何用户提供的数据传递到该构造中

在我开始讨论这个例子之前,我将使用的类的位置是在或上。
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);
就这样!对于大多数等式,您可以使用这样的解析器,不管它多么复杂和嵌套,而不必求助于“邪恶的
eval

因为我真的不想这只是为了让我的类在里面,这里有一些其他的选择。我对自己的电脑很熟悉,因为我已经用了8年了^^




我不太清楚以前在GitHub上发现的其他操作发生了什么,不幸的是,我没有给它添加书签,但它与包含解析器的大型浮点操作有关

无论如何,我想确保在这里用PHP解方程的答案不会指向所有未来的搜索者
eval
,因为这是谷歌搜索的顶部^^

在论坛中,有人没有进行
eval
就成功了。也许你可以试试?感谢他们,我刚刚找到了

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  

在这里也可以看到这个答案:

请注意,此解决方案不符合BODMAS,但您可以在求值字符串中使用括号来克服此问题

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

下面是我编写的有点冗长的代码。它确实符合BOMDAS,但不带
eval()
,但不具备执行复杂/高阶/插入式表达式的能力。这种无库方法将表达式分开,并系统地减少组件数组,直到删除所有运算符。它当然适用于示例表达式:
2-1
;)

  • preg_match()
    检查每个运算符的每一侧都有一个数字子字符串
  • preg_split()
  • array\u search()
    查找目标运算符在数组中存在时的索引
  • array\u splice()
    将运算符元素及其两侧的元素替换为一个新元素,该新元素包含删除的三个元素的数学结果
  • **更新为允许负数**

    代码:()

    $expression=“-11+3*1*4/-6-12”;
    if(!preg\u match('~^-?\d*\.?\d+([*/+-]-?\d*\.?\d+*$$,$expression)){
    回显“无效表达式”;
    }否则{
    
    $components=预分割('~(?As create_函数被弃用,我完全需要另一种轻量级的解决方案来计算字符串作为数学。花了几个小时后,我想出了以下方法。顺便说一句,我不在乎括号,因为在我的例子中我不需要。我只需要一些正确符合运算符优先级的东西

    更新:我也添加了括号支持。请检查这个项目

    函数evalAsMath($str){
    $error=false;
    $div_mul=false;
    $add_sub=false;
    $result=0;
    $str=preg\u replace('/[^\d\.\+\-\*\/]/i',''$str);
    $str=rtrim(trim($str,'/*+'),'-');
    如果((strpos($str,“/”)!==false | | strpos($str,“*”)!==false)){
    $div_mul=true;
    $operators=数组('*','/');
    while(!$error&&$operators){
    $operator=array_pop($operators);
    while($operator&&strpos($str,$operator)!==false){
    如果($error){
    打破
    }
    $regex='/([\d\.]+)\'.$operator.'(\-?[\d\.]+)/';
    预匹配($regex,$str,$matches);
    if(isset($matches[1])&isset($matches[2])){
    如果($operator='+')$result=(float)$matches[1]+(float)$matches[2];
    如果($operator='-')$result=(float)$matches[1]-(float)$matches[2];
    如果($operator='*')$result=(float)$matches[1]*(float)$matches[2];
    如果($operator=='/')){
    如果((浮动)$匹配[2]){
    $result=(float)$matches[1]/(float)$matches[2];
    }否则{
    $error=true;
    }
    }
    $str=preg_replace($regex,$result,$str,1);
    $str=str_replace(数组('+'、'-'、'-+'、'+-')、数组('+'、'+'、'-'、'-')、$str);
    }否则{
    $error=true;
    
    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
    
    $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
    }
    
    function evalAsMath($str) {
    
       $error = false;
       $div_mul = false;
       $add_sub = false;
       $result = 0;
    
       $str = preg_replace('/[^\d\.\+\-\*\/]/i','',$str);
       $str = rtrim(trim($str, '/*+'),'-');
    
       if ((strpos($str, '/') !== false ||  strpos($str, '*') !== false)) {
          $div_mul = true;
          $operators = array('*','/');
          while(!$error && $operators) {
             $operator = array_pop($operators);
             while($operator && strpos($str, $operator) !== false) {
               if ($error) {
                  break;
                }
               $regex = '/([\d\.]+)\\'.$operator.'(\-?[\d\.]+)/';
               preg_match($regex, $str, $matches);
               if (isset($matches[1]) && isset($matches[2])) {
                    if ($operator=='+') $result = (float)$matches[1] + (float)$matches[2];
                    if ($operator=='-') $result = (float)$matches[1] - (float)$matches[2]; 
                    if ($operator=='*') $result = (float)$matches[1] * (float)$matches[2]; 
                    if ($operator=='/') {
                       if ((float)$matches[2]) {
                          $result = (float)$matches[1] / (float)$matches[2];
                       } else {
                          $error = true;
                       }
                    }
                    $str = preg_replace($regex, $result, $str, 1);
                    $str = str_replace(array('++','--','-+','+-'), array('+','+','-','-'), $str);
             } else {
                $error = true;
             }
          }
        }
    }
    
      if (!$error && (strpos($str, '+') !== false ||  strpos($str, '-') !== false)) {
         $add_sub = true;
         preg_match_all('/([\d\.]+|[\+\-])/', $str, $matches);
         if (isset($matches[0])) {
             $result = 0;
             $operator = '+';
             $tokens = $matches[0];
             $count = count($tokens);
             for ($i=0; $i < $count; $i++) { 
                 if ($tokens[$i] == '+' || $tokens[$i] == '-') {
                    $operator = $tokens[$i];
                 } else {
                    $result = ($operator == '+') ? ($result + (float)$tokens[$i]) : ($result - (float)$tokens[$i]);
                 }
             }
          }
        }
    
        if (!$error && !$div_mul && !$add_sub) {
           $result = (float)$str;
        }
        return $error ? 0 : $result;
    }