【问题标题】:Algorithm for solving boolean variables in PHPPHP中求解布尔变量的算法
【发布时间】:2014-12-07 00:43:59
【问题描述】:

下面的关联数组表示不同的变量(由键值标识)和它们各自的逻辑运算符以与它们的邻居进行比较 - 它们的邻居是它们下面的变量。

Array(
      [x] => or
      [y] => and
      [z] => or
      [v] => null
     )

我正在尝试找出一种算法,该算法将采用上述数据结构并将其转换为以下表达式:

$result = lookup('x') || lookup('y') && lookup('z') || lookup('v');

其中lookup( $id ) 是一个函数,它查找给定字符串$id 的布尔值并返回它。因此,如果 x = true、y = true、z = false 和 v = false,则上面的计算结果为:

$results = true || true && false || false; // should evaluate to true

这是我目前所拥有的:

$bool_vars = array( 'x' => 'or', 'y' => 'and', 'z' => 'or', 'v' => null);

$keys = array_keys( $bool_vars ); // Grab the variable identifiers
$result = lookup( $keys[0] ); // Get the bool value of the first variable

// If there is more than one var, we need to evaluate the boolean expression
if( count($keys) > 1 ){
    foreach( $keys as $k => $key ){

        // No need to evaluate the last element since it has no neighbor
        if( $k + 1 == count( $keys ) ){ break; }

        $operator = $bool_vars[ $key ]; // Get the logical operator to use

        // Filter by operator
        switch( $operator ){
            case 'or':

                // Get the bool value of the next var
                $result = $result || isset( lookup( $keys[$k + 1] ) ); 
                break;

            case 'and':

                $result = $result && isset( $lookup( $keys[$k + 1] ) );
                break;

            default:
                continue;
        }
    }
}

return $result;

只是想用另一双眼睛来确保上述内容有意义 - 我已经多次运行此算法,但似乎有几次它没有返回正确的布尔值。

【问题讨论】:

  • v 出现在 z 之后是哪种语言?

标签: php algorithm boolean-logic boolean-expression


【解决方案1】:

大声说出来几乎是可怕的,但您发现eval 实际上是一个有效的解决方案而不是其本身的问题的罕见情况之一。只需将您的输入“编译”到 PHP 中,您的生活就会轻松一千倍。

例如:

$code = 'return ';
foreach($keys as $value => $op) {
  $code .= '$'.$value;
  switch($op) {
    case 'and':  $code .= ' && '; break;
    case 'or':   $code .= ' || '; break;
  }
}
$result = eval($code);

我当然在这里假设输入是可信的,否则您将需要一些适当的验证来防止任意代码注入。不过,$value 上的简单 ctype_alpha 可能就足够了。

实际上,使用您的 lookup 函数,它变得更加容易:

$code = 'return ';
foreach($keys as $value => $op) {
  $code .= lookup($value) ? 'true' : 'false';
  switch($op) {
    case 'and':  $code .= ' && '; break;
    case 'or':   $code .= ' || '; break;
  }
}
$result = eval($code);

这是完全安全的,而且比你能想到的任何东西都要短。

【讨论】:

    【解决方案2】:

    您尝试实现的称为Abstract Syntax Tree。这特别用于制作编译器和解释器。它是您的问题类型的实用表示,因为它可以处理运算符优先级,而您的平面表示很难做到这一点。

    在您的情况下,通过阅读您的代码,我们可以看到所有运算符具有相同的左优先级,并且您的数组是从左到右解析的,所以

    true || true && false || false
    

    由您的算法评估为:

    ((true || true) && false) || false
    

    计算结果为false

    我强烈建议您不要使用平面语法来表示操作数和运算符,而是使用基于树的结构来处理优先级和分组括号,例如:

    $tree = [
       'and' => [
            [ 'or' => ['x', 'y'] ],
            [ 'or' => ['z', 'v'] ]
       ]
    ];
    

    代表:

    (x || y) && (z || v)
    

    这个递归代码可以评估它:

    function evalAnd($arr) {
        return evalTree($arr[0]) && evalTree($arr[1]);
    }
    
    function evalOr($arr) {
        return evalTree($arr[0]) || evalTree($arr[1]);
    }
    
    function evalTree($tree) {
        if (is_array($tree) && array_key_exists('and', $tree)) {
            return evalAnd($tree['and']);
        }
        elseif (is_array($tree) && array_key_exists('or', $tree)) {
            return evalOr($tree['or']);
        }
        else {
            return lookup($tree);
        }
    }
    
    evalTree($tree);
    

    【讨论】:

    • In PHP, && has higher precedence than ||,所以我给出的示例将评估为true。虽然点到了 AST。对于我的特定应用程序,我对分组或优先级不感兴趣,只是为了获得布尔表达式的整体结果。
    • 我知道这些运算符的优先级,我只是编了一些例子,没有 100% 准确地回答你的问题 :)
    猜你喜欢
    • 2013-11-11
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    • 2017-01-02
    相关资源
    最近更新 更多