요즘 할 일이 없을 때 PHP로 파싱 프로그램을 작성했습니다.
예: (21*12-23-(21+14-(21-31/3+(14-21*12-14))+54)-21)+21*25-22 * 26
그러면 분석결과는 -169.33 입니다.
이제 코드를 게시하겠습니다. 잘못된 점이 있으면 동료 프로그래머에게 지적해 주세요.
if(isset($_GET['sizhi'])){ $sizhi=$_GET['sizhi']; if(!checkSizhi($sizhi)){ echo('算式不合法,检查括号是否配对'); }else{ $sizhi=priority($sizhi); echo(calculate($sizhi)); } } //检查算式是否合法 function checkSizhi($sizhi){ $Amatch=array(); $pattern='/((\d|!)\()|([-\+\*\/]\))|[^-\+\*\/!\d\(\)]/'; if(preg_match($pattern,$sizhi,$Amatch)>0){ echo('不合法的元素:'); print_r($Amatch); return false; }else{ $kuohao=0; for($i=0,$k=strlen($sizhi);$i<$k;$i++){ if($sizhi[$i]=="("){ $kuohao++; } if($sizhi[$i]==")"){ $kuohao--; if($kuohao<0)return false; } } if($kuohao!=0)return false; return true; } } //获得优先权 处理括号内的内容 function priority($sizhi,$start=0){ for($i=$start;$i<strlen($sizhi);$i++){ if($sizhi[$i]=="("){ //递归深内层括号 $sizhi=priority($sizhi,$i+1); } if($sizhi[$i]==")"){ $str=calculate(trim(substr($sizhi,$start-1,$i-$start+2),"\(\)")); //用计算结果替换括号内的东西 $sizhi=substr_replace($sizhi,$str,$start-1,$i-$start+2); //返回内层替换后的字符串 return $sizhi; } } return $sizhi; } //计算结果 function calculate($sizhi){ //在算式前加上+ 号 以便后面用正则提取 if($sizhi[0]!="-"){ $sizhi='+'.$sizhi; } //处理阶乘 //判断阶乘是否合法 因为3的双重阶乘就就已经很大了 $erropar='/(\.[0-9]+!+)|!{3,}/'; $par='/[1-9][0-9]*!{1,2}/'; if(preg_match($erropar, $sizhi)>0){ echo("阶乘阶段出问题,请改算式"); exit(); }else{ //替换所有阶乘的部分 $sizhi=preg_replace_callback($par,function($siz){ return calculateFactorial($siz[0]); } , $sizhi); } //交换符号与数字并计算 return change($sizhi); } //计算阶乘 function calculateFactorial($sizhi){ for ($i=0; $i <strlen($sizhi); $i++) { if($sizhi[$i]=='!'){ $number=substr($sizhi,0,$i)*1; $product=1; for($j=1;$j<=$number;$j++){ $product*=$j; } $sizhi=substr_replace($sizhi,$product,0,$i+1); //递归处理多重阶乘 return calculateFactorial($sizhi); } } return $sizhi; } function change($sizhi){ if($sizhi[0]!="-"){ $sizhi='+'.$sizhi; } $array=array(); //提取单个算式 并保存到数组中 提取结果为:例如 +5-3*8/5 提取结果为:+5 -3 *8 /5 $par='/[-\+\/\*]-?(\d\.?)+/'; preg_match_all($par, $sizhi, $array); return sum($array[0]); } //计算只含加减乘除的算式 function sum($ziArry){ for($i=0;$i<count($ziArry);$i++){ //先计算乘除 遍历整个算式数组 如果有一个数组前边的符号为乘号或者除号 则与前数想乘除 //并把前一个清空,然后清除数组中空的元素 if($ziArry[$i][0]=="*"||$ziArry[$i][0]=="/"){ $ziArry[$i]=$ziArry[$i-1][0].calut(substr($ziArry[$i-1],1),substr($ziArry[$i],1),$ziArry[$i][0]); $ziArry[$i-1]=""; } } //清除数组中空的元素 $ziArry=calerNu($ziArry); //计算加减 for($i=0;$i<count($ziArry);$i++){ if($i==0&&$ziArry[0][0]=="-"){ $ziArry[1]='+'.calut($ziArry[0],substr($ziArry[1],1),$ziArry[1][0]); $ziArry[0]="+0"; }else if($i!=0){ $ziArry[$i]=$ziArry[$i-1][0].calut(substr($ziArry[$i-1],1),substr($ziArry[$i],1),$ziArry[$i][0]); $ziArry[$i-1]=""; } } //去符号 $relus=calerNu($ziArry)[0]; if(($relus[0]==$relus[1]&&$relus[0]=='-')||($relus[0]==$relus[1]&&$relus[0]=='+')){ return substr($relus,2); } if(($relus[0]=='+'&&$relus[0]=='-')||($relus[0]=='-'&&$relus[0]=='+')){ return '-'.substr($relus,2); } return substr($relus,1); } //清除数组中的空元素 function calerNu($array){ for($i=0;$i<count($array);$i++){ if($array[$i]==""){ for ($k=$i; $k<count($array)-1; $k++) { $array[$k]=$array[$k+1]; } $last=array_pop($array); return calerNu($array); } } return $array; } function calut($numberone,$numbertwo,$fu){ $number $numbertwo=$numbertwo*1; switch ($fu) { case '-': return $numberone-$numbertwo; case '+': return $numberone+$numbertwo; case '*': return $numberone*$numbertwo; case '/': $str=(string)$numberone/$numbertwo; //如果除不尽则保留小数点后两位 $par='/-?\d+\.\d{2}/'; $array=array(); if(preg_match($par, $str,$array)>0){ $str=$array[0]; } return $str; } }
위 내용은 관련 내용을 포함하여 계산식의 분석 알고리즘을 소개하고 있으며, PHP 튜토리얼에 관심이 있는 친구들에게 도움이 되기를 바랍니다.