Ayer necesitaba ejecutar una ecuación guardada en la base de datos.
Como $var = $fetch['ecuacion']; lo almacena como simple texto, he recurrido a
eval poniendo:
eval("\$return=" . $equation . ";");
echo $return;
// Si hicieramos $equation = "2*2+45"; imprimiria 49...
Hasta ahí bien, pero el problema llegó cuando quise hacer potencias, para hacerlas yo uso ^ (por la calculadora, por lo que 2
3 sería 2^3.
Pero PHP requiere usar pow(), así que me estrujé un poco la cabeza y saqué esta función, tal vez muy mejorable, y que funciona perfectamente.
function parseEquation($eq) {
// IPER FUNSION POR WESTWEST :D
$rest_eq = $eq;
$prev_eq = '';
$pos = strpos($rest_eq, '^');
while($pos !== false) {
settype($rest_eq, 'string');
$prev = 0;
$array = array('(', '+', '-', '*', '/');
$addp = 0;
foreach($array as $operator) {
$op = strrpos(substr($rest_eq, 0, $pos), $operator);
if($op !== false && $op >= $prev) {
$prev = $op;
$addp = 1;
}
}
$prev += $addp;
$next = strlen($rest_eq)-1;
$array = array(')', '+', '-', '*', '/', '^');
$addp = 0;
foreach($array as $operator) {
$op = strpos(substr($rest_eq, $pos+1), $operator);
if($op !== false && $op < $next) {
$next = $op;
$addp = $pos;
}
}
$next += $addp;
$prev_eq .= substr($rest_eq, 0, $prev).'pow('.substr($rest_eq, $prev, ($pos-$prev)).', '.substr($rest_eq, $pos+1, ($next-$pos)).')';
$rest_eq = substr($rest_eq, $next+1);
$pos = strpos($rest_eq, '^');
}
$eq = $prev_eq.$rest_eq;
eval("\$return=" . $eq . ";");
return round($return);
}
Explico un poco por encima, así de paso sirve de tutorial.
Primero con strpos determino donde hay un ^, esto devuelve false si no encuentra, así que el while se eecutará mientras haya alguno (notad que es !==, no !=).
Primero, con un foreach obtengo la mayor posición de un caracter que delimite a los números, ya que al lado irá "pow(", despues hago lo mismo pero tras el ^, y busco el primero.
El $addp es para que cuadre todo.
Despues "corto" la cadena y la monto en $prev_eq, en $rest_eq, la cadena que se analiza pongo lo que queda y, si es necesario, vuelve a empezar.
Luego lo paso por eval, lo redondeo y devuelvo.
Funciones:
evalstrposstrrposNo tiene una utilidad general, pero tal vez le sirva a alguien.
Salu2!