Mitchell Weiss
Mitchell Weiss

Reputation: 93

Evaluate multiple conditions stored as a string

I have a few strings stored in a database which contain specific rules which must be met. The rules are like this:

>25
>25 and < 82
even and > 100
even and > 10 or odd and < 21

Given a number and a string, what is the best way to evaluate it in PHP?

eg. Given the number 3 and the string "even and > 10 or odd and < 21" this would evaluate to TRUE

Thanks

Mitch

Upvotes: 2

Views: 227

Answers (2)

jcsanyi
jcsanyi

Reputation: 8174

As mentioned in the comments, the solution to this can be very simple or very complex.

I've thrown together a function that will work with the examples you've given:

function ruleToExpression($rule) {
    $pattern = '/^( +(and|or) +(even|odd|[<>]=? *[0-9]+))+$/';
    if (!preg_match($pattern, ' and ' . $rule)) {
        throw new Exception('Invalid expression');
    }
    $find = array('even', 'odd', 'and', 'or');
    $replace = array('%2==0', '%2==1', ') && ($x', ')) || (($x');
    return '(($x' . str_replace($find, $replace, $rule) . '))';
}

function evaluateExpr($expr, $val) {
    $x = $val;
    return eval("return ({$expr});");
}

This supports multiple clauses separated by and and or, with no parentheses and the and always being evaluated first. Each clause can be even, odd, or a comparison to a number, allowing >, <, >=, and <= comparisons.

It works by comparing the entire rule against a regular expression pattern to ensure its syntax is valid and supported. If it passes that test, then the string replacements that follow will successfully convert it to an executable expression hard-coded against the variable $x.

As an example:

ruleToExpression('>25');
// (($x>25))

ruleToExpression('>25 and < 82');
// (($x>25 ) && ($x < 82))

ruleToExpression('even and > 100');
// (($x%2==0 ) && ($x > 100))

ruleToExpression('even and > 10 or odd and < 21');
// (($x%2==0 ) && ($x > 10 )) || (($x %2==1 ) && ($x < 21))

evaluateExpr(ruleToExpression('even and >25'), 31);
// false

evaluateExpr(ruleToExpression('even and >25'), 32);
// true

evaluateExpr(ruleToExpression('even and > 10 or odd and < 21'), 3);
// true

Upvotes: 2

Dennis Tsoumas
Dennis Tsoumas

Reputation: 142

Why don't you translate the string even to maths? If you use mods you can write it like that $number % 2 == 0. In that case, your example will be:

if(($number % 2 == 0 && $number > 10 ) || ($number % 2 != 0 && $number < 21)){
//Then it is true!
}

Upvotes: 0

Related Questions