是否可以显示php如何计算问题的解决方案。
例如:
<?php
$equation = (5+1)*3/9; // outputs 2
?>
如果希望看到它处理的所有步骤都来到该解决方案: IE:
(5 + 1)= 6
6 * 3 = 18
18/9 = 2
答案 0 :(得分:3)
简短的回答是“也许”。在运行时期间不可能像你期望的那样挂钩PHP内部。但是,有一种替代方法可以使用外部解析器来接近它。
原因是,PHP在内部使用抽象语法树(AST)来定义处理步骤以及通过创建更好的二进制表示作为OpCache来优化执行,以避免再次解析和处理相同的脚本再一次。
因此,如果您需要了解有关PHP中的处理的更多信息,您可以考虑分析PHP C源代码:
ZEND_ADD
,ZEND_SUB
,ZEND_MUL
,ZEND_DIV
add_function
,sub_function
,mul_function
,div_function
nikic/php-parser
也可以在PHP中重新实现AST解析器,请参阅https://github.com/nikic/PHP-Parser。
以下示例将原始问题的表达式$equation = (5+1)*3/9; // outputs 2
放入专用的math.php
文件中。使用以下CLI命令执行解析器:
composer require nikic/php-parser
vendor/bin/php-parse math.php
将输出$equation = (5+1)*3/9; // outputs 2
的解析语法树(基本上是原始问题的答案):
====> File math.php:
==> Node dump:
array(
0: Stmt_Expression(
expr: Expr_Assign(
var: Expr_Variable(
name: equation
)
expr: Expr_BinaryOp_Div(
left: Expr_BinaryOp_Mul(
left: Expr_BinaryOp_Plus(
left: Scalar_LNumber(
value: 5
)
right: Scalar_LNumber(
value: 1
)
)
right: Scalar_LNumber(
value: 3
)
)
right: Scalar_LNumber(
value: 9
)
)
)
)
1: Stmt_Nop(
comments: array(
0: // outputs 2
)
)
)
通过阅读https://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html(上面提到的PHP AST解析器的作者),可能会发现有关分析PHP处理的更多信息。但是,本节没有给出问题的额外答案 - 更多的是概述替代方案以及它们实际揭示的内容。
php -d opcache.enable_cli=1 -d opcache.opt_debug_level=0x10000 math.php
在CLI上下文中执行的上述命令启用OpCache调试并输出以下内容:
$_main: ; (lines=3, args=0, vars=1, tmps=1)
; (before optimizer)
; /var/www/developer/math.php:1-4
L0: EXT_STMT
L1: ASSIGN CV0($equation) int(2)
L2: RETURN int(1)
上面的调试输出只包含结果int(2)
,但不包含已为语法树确定的相应步骤 - 这一点非常明显,因为它们不是优化版本所必需的。
这可以通过查看生成的OpCache二进制文件来验证:
php -d opcache.enable_cli=1 -d opcache.opt_debug_level=0x10000 \
-d opcache.file_cache=/var/www/developer/opcache/ \
-d opcache.file_cache_only=1 math.php
hexdump opcache/08202de11af2c60edca0b5438eeefab6/var/www/developer/math.php.bin -C
(我的工作目录是/var/www/developer/
,其中有一个子目录opcache/
)
00000210 2f 76 61 72 2f 77 77 77 2f 64 65 76 65 6c 6f 70 |/var/www/develop|
00000220 65 72 2f 6d 61 74 68 2e 70 68 70 00 75 7f 00 00 |er/math.php.u...|
00000230 28 32 60 aa 75 7f 00 00 30 32 60 aa 75 7f 00 00 |(2`.u...02`.u...|
00000240 38 32 60 aa 75 7f 00 00 40 32 60 aa 75 7f 00 00 |82`.u...@2`.u...|
00000250 02 00 00 00 00 00 00 00 04 00 00 00 ff ff ff ff |................| <--
00000260 01 00 00 00 00 00 00 00 04 00 00 00 ff ff ff ff |................|
00000270 e9 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000280 00 00 00 00 00 00 00 00 02 00 00 00 65 08 08 08 |............e...|
00000290 e9 0b 00 00 00 00 00 00 50 00 00 00 00 00 00 00 |........P.......|
000002a0 00 00 00 00 00 00 00 00 02 00 00 00 26 10 01 08 |............&...|
000002b0 e9 0b 00 00 00 00 00 00 10 00 00 00 00 00 00 00 |................|
000002c0 00 00 00 00 ff ff ff ff 04 00 00 00 3e 01 08 08 |............>...|
000002d0 88 02 00 00 00 00 00 00 00 00 00 00 06 02 00 00 |................|
000002e0 cb 5b 29 c4 00 e7 1a 80 08 00 00 00 00 00 00 00 |.[).............|
000002f0 65 71 75 61 74 69 6f 6e 00 32 60 aa 75 7f 00 00 |equation.2`.u...|
上面的hexdump只显示了OpCache文件的结尾。标记行中的第一个字节(0x00000250
)已包含优化结果02
。对于给定的示例,没有进一步指向运算符(例如ZEND_MUL
)和整数文字5
,1
,3
或9
的指针。因此,常数方程的结果已经直接存储在OpCache中。
答案 1 :(得分:2)
据我所知,您正在寻找的是一个数学表达式求值器,能够解析输入字符串并逐步计算,直到达到最终结果。
我花了一些时间来建立一个,这是最终的代码:
<?php
function evaluate($input)
{
if (!preg_match('/^[+\-*\/\(\)\.\d]+$/', $input))
return array('NaN');
$steps = array();
$steps[] = $input;
$input = preg_replace('/(\d+(?:\.\d+)?[*\/]\d+(?:\.\d+)?)/', '(\1)', $input);
while (strpos($input, '(') || strpos($input, ')'))
{
$input = preg_replace_callback('/\(([^\(\)]+)\)/', 'evaluate_callback', $input);
$steps[] = $input;
$input = preg_replace('/(\d+(?:\.\d+)?[*\/]\d+(?:\.\d+)?)/', '(\1)', $input);
}
if (preg_match('/(?:\-?\d+(?:\.?\d+)?[\+\-\*\/])+\-?\d+(?:\.?\d+)?/', $input, $match))
{
$steps[] = strval(0 + eval('return '.$match[0].';'));
return $steps;
}
return array('NaN');
}
function evaluate_callback($input)
{
if (is_numeric($input[1]))
return $input[1];
if (preg_match('/(?:\-?\d+(?:\.?\d+)?[\+\-\*\/])+\-?\d+(?:\.?\d+)?/', $input[1], $match))
return strval(0 + eval('return '.$match[0].';'));
return '0';
}
?>
这是一个用法示例:
$input = '(7.4-0.2*(1+2.1*0.3))*3-(4.1*2.4-4*0.7)+1*0.4';
$result = evaluate($input);
print_r($result);
Array
(
[0] => (7.4-0.2*(1+2.1*0.3))*3-(4.1*2.4-4*0.7)+1*0.4
[1] => (7.4-0.2*(1+0.63))*3-(9.84-2.8)+0.4
[2] => (7.4-0.2*1.63)*3-7.04+0.4
[3] => (7.4-0.326)*3-7.04+0.4
[4] => 7.074*3-7.04+0.4
[5] => 21.222-7.04+0.4
[6] => 14.582
)
访问this link,以便亲自尝试一个有效的演示。
我知道,这是非常原始的,但我认为这是一个很好的起点,为了改善它,可以做很多事情。它只处理加法,减法,乘法和除法。嵌套级别只能使用圆括号定义。它可能不太详细,因为可以使用单个eval
执行的直接算术步骤不会被分割为子步骤(我在信号上指的是链式加法和/或减法)以及在一次性完成相同的嵌套级别。
答案 2 :(得分:1)
基本的想法是实现你的目标是使用像BODMAS这样的东西,我首先使用括号( )
,然后使用'*'
,'/'
,'+'
和{{ 1}}最后。
您可以创建一个函数,首先将括号与preg_match_all
匹配,然后先执行,然后使用eval()
方法逐步执行其余操作,
'-'
上述代码的输出为:<?php
$str = '(5+1)*3/9';
$count = 0;
echo "step".($count+1)." : $str \n<br/>";
function bodmas($eq,$count,$op){
foreach (['*','/','+','-'] as $key => $symbol) {
preg_match_all("!\d+(\.\d+)?\\$symbol\d+(\.\d+)?!", $eq, $matches);
if(count($matches[0])){
foreach ($matches[0] as $key2 => $match) {
$count++;
eval("\$result = $match;");
$eq = str_replace($match, $result, $eq);
if($op){
echo "step".($count+1)." : $eq \n<br/>";
}
singleton($eq,$count);
}
}
}
}
preg_match_all("/\([^\^(\)]*\)/", $str, $matches);
//print_r($matches);
foreach($matches[0] as $key=>$value){
$value = str_replace(["(",")"], ["",""], $value);
$eq = bodmas($value,$count,false);
$count++;
eval("\$result = $value;");
$str = str_replace("($value)", $result, $str);
echo "step".($count+1)." : $str \n<br/>";
}
bodmas($str,$count,true);
function singleton($str,$count){
preg_match_all("/\(\d+(\.\d+)?\)/", $str, $matches);
if(count($matches[0])){
foreach($matches[0] as $key=>$value){
$str = str_replace(["(",")"], ["",""], $str);
}
bodmas($str,$count,true);
}
}
?>
(5+1)*3/9
另一个例子:step1 : (5+1)*3/9
step2 : 6*3/9
step3 : 18/9
step4 : 2
输出是:
((5*1)*3/9)*2
注意:这可能有一些软砖,但你可以使用这种结构。不要期望任何能够为您提供所有可能条件的人。我们只能通过小件代码帮助您。祝好运。
答案 3 :(得分:0)
是的,一切皆有可能,但是处理很快,你需要建立你的 自己的执行此操作的算法
所以我们都知道算术运算的规则/ * + -
示例
用户输入:8/2+2=6
现在我们知道的输出是8/2=4
然后是4+2=6
因此我们需要执行后台执行此操作的操作
你需要执行拆分和计算以及批量堆栈和队列来通过创建算法来处理这个问题。
答案 4 :(得分:0)
这是一个解决方程(solve_equation
函数)的示例代码。
这基本上找到了简单的方程(*,/,+, - )并逐个求解(通过使用preg_match
,“正则表达式匹配”找到小方程)。最终它通过showing all the steps
解决了所有等式。
function str_replace_first($from, $to, $content)
{
$from = '/'.preg_quote($from, '/').'/';
return preg_replace($from, $to, $content, 1);
}
function solve_equation($equation)
{
echo "<pre>Equation. Begin: ".$equation."</pre>";
$original=$equation;
$run=true;
while($run)
{
$run=false;
// multiplication and division with BRACKETS
while(preg_match('/\((\-)?([0-9])+[\*\/](\-)?([0-9])+\)/',$equation,$m)>0)
{
$current=$m[0];
$split=preg_split("/\*/",$current);
if(sizeof($split)==2)
{
// multiplication
$result=(int)(intval(substr($split[0],1))*intval(substr($split[1],0,strlen($split[1])-1)));
}
else
{
$split=preg_split("/\//",$current);
// division
$result=(int)(intval(substr($split[0],1))/intval(substr($split[1],0,strlen($split[1])-1)));
}
$equation=str_replace($current, $result, $equation);
echo "<pre>".$current."=".$result."</pre>";
echo "<pre>".$equation."=?</pre>";
}
// addition and substraction with BRACKETS
while(preg_match('/\((\-)?([0-9])+[\+\-](\-)?([0-9])+\)/',$equation,$m)>0)
{
$current=$m[0];
$split=preg_split("/\+/",$current);
if(sizeof($split)==2)
{
// addition
$result=(int)(intval(substr($split[0],1))+intval(substr($split[1],0,strlen($split[1])-1)));
}
else
{
$split=preg_split("/\-/",$current);
// substraction
$result=(int)(intval(substr($split[0],1))-intval(substr($split[1],0,strlen($split[1])-1)));
}
$equation=str_replace($current, $result, $equation);
echo "<pre>".$current."=".$result."</pre>";
echo "<pre>".$equation."=?</pre>";
}
// multiplication and division
while(preg_match('/(\-)?([0-9])+[\*\/](\-)?([0-9])+/',$equation,$m)>0)
{
$current=$m[0];
$split=preg_split("/\*/",$current);
if(sizeof($split)==2)
{
// multiplication
$result=(int)(intval($split[0])*intval($split[1]));
}
else
{
$split=preg_split("/\//",$current);
// division
$result=(int)(intval($split[0])/intval($split[1]));
}
$equation=str_replace($current, $result, $equation);
echo "<pre>".$current."=".$result."</pre>";
echo "<pre>".$equation."=?</pre>";
}
// addition and substraction
while(preg_match('/(\-)?([0-9])+[\+\-](\-)?([0-9])+/',$equation,$m)>0)
{
$current=$m[0];
$split=preg_split("/\+/",$current);
if(sizeof($split)==2)
{
// multiplication
$result=(int)(intval($split[0])+intval($split[1]));
}
else
{
$split=preg_split("/\-/",$current);
// division
$result=(int)(intval($split[0])-intval($split[1]));
}
$equation=str_replace($current, $result, $equation);
echo "<pre>".$current."=".$result."</pre>";
echo "<pre>".$equation."=?</pre>";
}
// echo "<pre>Equation=".$equation."</pre>";
// echo "<pre>Start Brackets:</pre>";
while(preg_match('/\((\-)?([0-9])+\)/',$equation,$m)>0)
{
$run=true;
$current=$m[0];
$equation=str_replace($current, substr($current, 1, strlen($current)-2), $equation);
// echo "<pre>Equation=".$equation."</pre>";
}
}
echo "<pre>$original=$equation</pre>";
}
$equation="32+64*(45-12*3)";
solve_equation($equation);
?>
此代码的输出:
Equation. Begin: 32+64*(45-12*3)
-12*3=-36
32+64*(45-36)=?
32+64=96
96*(45-36)=?
45-36=9
96*(9)=?
96*9=864
864=?
32+64*(45-12*3)=864