如 cmets 中所述,解决此问题的方法可能非常简单,也可能非常复杂。
我整理了一个函数,可以与您给出的示例一起使用:
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});");
}
这支持由and 和or 分隔的多个子句,没有括号并且总是首先评估and。每个子句可以是 even、odd 或与数字的比较,允许对 >、<、>= 和 <= 进行比较。
它通过将整个规则与正则表达式模式进行比较来确保其语法有效且受支持。如果它通过了该测试,那么随后的字符串替换将成功地将其转换为针对变量 $x 硬编码的可执行表达式。
举个例子:
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