0

I would like to write a function that will process formulas that are comprised of array keys. For example, (1+3+5+7-8)*9 or (1-3+5)/6 and etc Any suggestions?

EDIT: I think it's better to think of this as an excel grid, with field coordinates being the array keys and one of the fields being the formula field (e.g. A1+A2-B2*B3)

pistolshrimp
  • 1,009
  • 2
  • 14
  • 21

2 Answers2

1


function convert_formula($formula, $formula_array) {
    $callback = function($matches) use ($formula_array) {return $formula_array[(int) $matches[0]];};
    $converted = preg_replace_callback("/[0-9]+/", $callback, $formula);
    return eval("return $converted;");
    }

$test_formula = '(3-1) * (3-10)';
$test_formula_array = array(323,67,82,56, 10 => 3);

echo convert_formula($test_formula, $test_formula_array);



Requires PHP 5.3.+ for anon functions. You'll want to first validate the $formula argument to ensure it accepts only numbers and math symbols before you eval it within the function.

Edit: just going by some assumption that this is a tool to instruct students on math and that you already have a pre-built set of formulas to reference... as eval is one of the most dangerous functions of PHP, perhaps you might consider running this client side using javascript. When you build the page, you simply dynamically create a base reference javascript array containing all possible values to be used in the formula. So this way, using javascript's eval function, the client builds and resolves the formula all on their end. That final evaluation is then passed back to your server which then validates the evaluation and gives a final "correct/wrong" response. Just a thought...

bob-the-destroyer
  • 3,164
  • 2
  • 23
  • 30
  • Thanks mr. destroyer. It works great! I am aware of the eval evil and the javascript eval approach was exactly what I planned to use. As I am not very well versed in js (yet), I figured obtaining the formula in php was easier for me. – pistolshrimp Dec 02 '10 at 05:31
  • @pistolshrimp: you're welcome. There will be some issues porting this function to javascript, such as no `use` keyword to auto-import a variable from parent scope into anon function local scope. Here's a SO question on javascript anon functions that will help here: http://stackoverflow.com/questions/1140089/how-does-an-anonymous-function-in-javascript-work. Also, no `preg_replace_callback` function, so a workaround is needed there. – bob-the-destroyer Dec 02 '10 at 05:54
1

Okay, this one really works.

$input = '0 + 1 + 2 + 3';
$input = preg_replace('/[^0-9\/\+\-\*]/', '', $input);

$array = array(23, 40, 6, 200);

function getAtIndex($i) {
    global $array;
    return isset($array[$i[0]]) ? $array[$i[0]] : 0;
}

$output = preg_replace_callback('/[0-9]+/', 'getAtIndex', $input);

eval('$output = ' . $output . ';');

Edit: now cleans input.

Jonah
  • 9,991
  • 5
  • 45
  • 79
  • Bron: even though your other example wouldn't go past 9, using `str_replace` like that was still pretty inventive. – bob-the-destroyer Dec 02 '10 at 05:30
  • @bob-the-destroyer: I haven't tested it yet, but I believe it would. Note the `+` in the regular expression. Did you test it? – Jonah Dec 07 '10 at 00:50