Reputation: 1339
I am trying to create a script that cleans a string from anything that is not a number or operator and then performs the calculation.
It works fine if, for example, the sting is How much is 25 + 35 then * 8 and then / 2
, but if the string is How much is 25.5 + 35.5 then * 8 and then / 2
, the result is wrong, as it does not consider the float in the numbers
I have tried using is_float
in the for
loop but without success.
here is a demo http://sandbox.onlinephpfunctions.com/code/c06295bbb567b667cfd65ff0d736330fea0e774b
Any idea what can I do to make it calculate them right?
$result = "How much is 25.5 + 35.5";
$allowed = array('1','2','3','4','5','6','7', '8', '9','0','-','+','/','*','.');
$regex = sprintf('/[^%s]/u', preg_quote(join($allowed), '/'));
$result = preg_replace($regex, '', $result);
$str = preg_replace('/\s+/', '', $result);
//Create calculation
$number = array();
$z = 0;
for ($i = 0; $i < iconv_strlen($str); $i++) {
if (is_numeric($str[$i])) {
$number[$z] .= $str[$i];
} else {
$z++;
$number[$z] = $str[$i];
$z++;
}
};
for ($i = 0; $i < count($number); $i++) {
$number[$i] = (int) $number[$i];
$i++;
$number[$i] = (string) $number[$i];
}
$res = $number[0];
for ($i = 0; $i < count($number); $i++) {
if ($number[$i+1] === '+') {
$res += $number[$i+2];
}elseif($number[$i+1] === '-'){
$res -= $number[$i+2];
}elseif($number[$i+1] === '*'){
$res *= $number[$i+2];
}elseif($number[$i+1] === '/'){
$res /= $number[$i+2];
}
$i++;
}
echo round($res,2);
Upvotes: 0
Views: 89
Reputation: 1668
Maybe you should just use eval
:
<?php
//Enter your code here, enjoy!
$result = "How much is 25.5 + 35.5";
$allowed = array('1','2','3','4','5','6','7', '8', '9','0','-','+','/','*','.');
$regex = sprintf('/[^%s]/u', preg_quote(join($allowed), '/'));
$result = preg_replace($regex, '', $result);
eval('$calculation = '.$result.';');
var_dump($calculation);
http://sandbox.onlinephpfunctions.com/code/ecbf77e8bed6c7d7bed93f97bde67ac48f46cff6
I just found this package: https://github.com/dbojdo/eval-math
Which solve the security problem for eval
.
But your user will still have to write (25.5+35.5) * 8 / 2
if you want to perform the addition first.
Upvotes: 0
Reputation: 5224
The issue is you are iterating over every character rather than keeping them together. You have:
Array
(
[0] => 25
[1] => .
[2] => 5
[3] => +
[4] => 35
[5] => .
[6] => 5
[7] =>
)
So:
if ($number[$i+1] === '+') {
$res += $number[$i+2];
is only matched once at index 3 then index 4's value is taken (e.g. 35) for the addition to 25
(index 0). The decimal values are ignored entirely.
I would use an approach like this:
$result = "How much is 25.5 + 35.5";
$allowed = array('1','2','3','4','5','6','7', '8', '9','0','-','+','/','*','.');
$regex = sprintf('/([%s]+)/u', preg_quote(join($allowed), '/'));
preg_match_all($regex, $result, $match);
switch($match[0][1]){
case '-':
echo $match[0][0] - $match[0][2];
break;
case '*':
echo $match[0][0] * $match[0][2];
break;
case '+':
echo $match[0][0] + $match[0][2];
break;
case '/':
echo $match[0][0] / $match[0][2];
break;
}
Upvotes: 1