Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
885 views
in Technique[技术] by (71.8m points)

math - Process mathematical equations in php

A user is allowed to enter any mathematical equation they like (with one variable):

x + 5

1 - x/2

(x/3) * (56/13)

These are stored as strings in the database. When they are retrieved I need to substitute 'x' for a number and check the value of the equation.

How could I do this?

I was considering writing a parser to deconstruct the strings and turn them into equations, however this sounds expensive and problematic. The other option is to pass them through eval (but I'm not a great fan of using eval if I can help it).

Any ideas?

UPDATE: I also need to be able to get the boolean value of something like "(x > 5)". This is not possible with evalMath

UPDATE 2: I need to fire lots of these a second. I've been looking into eval in php but cant get it to return a boolean for (5 > 4) however I noticed js would do it... maybe I should investigate node.js...

UPDATE 3: After having some fun trying out node.js (and getting it to work) I went back and got eval to work in PHP see: Can php eval return a boolean value?

So I will go with eval with a very very hardcore filter on user input.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

My standard answer to this question whenever it crops up:

Don't use eval (especially as you're stating that this is user input) or reinvent the wheel by writing your own formula parser.

Take a look at the evalMath class on PHPClasses. It should do everything that you've listed here.

EDIT

re: Unfortunately evalMath does not handle things like (x > 5)

change lines 177-179 to

$ops   = array('+', '-', '*', '/', '^', '_', '>', '<', '=');
$ops_r = array('+'=>0,'-'=>0,'*'=>0,'/'=>0,'^'=>0, '>' => 0, '<' => 0, '=' => 0); // right-associative operator?
$ops_p = array('+'=>0,'-'=>0,'*'=>1,'/'=>1,'_'=>1,'^'=>2, '>' => 0, '<' => 0, '=' => 0); // operator precedence

change line 184 to

if (preg_match("/[^ws+*^/().,-<>=]/", $expr, $matches)) { // make sure the characters are all good

add

case '>':
     $stack->push($op1 > $op2); break;
case '<':
     $stack->push($op1 < $op2); break;
case '=':
     $stack->push($op1 == $op2); break;

after line 321

and evalMath will now handle (x > 5), (x < 5) or (x = 5)

// instantiate a new EvalMath
$m = new EvalMath;
$m->suppress_errors = true;
// set the value of x
$m->evaluate('x = 3');
var_dump($m->evaluate('y = (x > 5)'));

Further Edit

Missed line 307 that should be modified to read:

if (in_array($token, array('+', '-', '*', '/', '^', '>', '<', '='))) {

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...