I am trying to perform calculations in a string and am wondering how to parse through a string expression with a combination of numbers and operations (+ addition, . concatenation, etc).
Ex: [11.0.0] would equal 1100 or [3+5] would equal 8.
I am trying to perform calculations in a string and am wondering how to parse through a string expression with a combination of numbers and operations (+ addition, . concatenation, etc).
Ex: [11.0.0] would equal 1100 or [3+5] would equal 8.
You'd usually tokenize the string and then parse the string, the way you want, into executable calculation logic to then execute.
While there are some PHP lexer library for tokenization, you'd probably need to write your own parser (cause only you would know the rules to your calculation syntax).
If you don't have any needs to formulate your own syntax, you're free to use existing library that does the whole thing for you.
You can use this to write math expressions in input fields (which is based on another answer).
$Cal = new Field_calculate();
$result = $Cal->calculate('5+7'); // 12
$result = $Cal->calculate('(5+9)*5'); // 70
$result = $Cal->calculate('(10.2+0.5*(2-0.4))*2+(2.1*4)'); // 30.4
This is the class that is used in above examples:
class Field_calculate {
const PATTERN = '/(?:\-?\d+(?:\.?\d+)?[\+\-\*\/])+\-?\d+(?:\.?\d+)?/';
const PARENTHESIS_DEPTH = 10;
public function calculate($input){
if(strpos($input, '+') != null || strpos($input, '-') != null || strpos($input, '/') != null || strpos($input, '*') != null){
// Remove white spaces and invalid math chars
$input = str_replace(',', '.', $input);
$input = preg_replace('[^0-9\.\+\-\*\/\(\)]', '', $input);
// Calculate each of the parenthesis from the top
$i = 0;
while(strpos($input, '(') || strpos($input, ')')){
$input = preg_replace_callback('/\(([^\(\)]+)\)/', 'self::callback', $input);
$i++;
if($i > self::PARENTHESIS_DEPTH){
break;
}
}
// Calculate the result
if(preg_match(self::PATTERN, $input, $match)){
return $this->compute($match[0]);
}
// To handle the special case of expressions surrounded by global parenthesis like "(1+1)"
if(is_numeric($input)){
return $input;
}
return 0;
}
return $input;
}
private function compute($input){
$compute = create_function('', 'return '.$input.';');
return 0 + $compute();
}
private function callback($input){
if(is_numeric($input[1])){
return $input[1];
}
elseif(preg_match(self::PATTERN, $input[1], $match)){
return $this->compute($match[0]);
}
return 0;
}
}