PHP中布尔变量的求解算法

PHP中布尔变量的求解算法,php,algorithm,boolean-logic,boolean-expression,Php,Algorithm,Boolean Logic,Boolean Expression,下面的关联数组表示不同的变量(由键值标识)及其各自的逻辑运算符,以便与它们的邻居进行比较—它们的邻居是它们下面的变量 Array( [x] => or [y] => and [z] => or [v] => null ) 我试图找出一种算法,将上面的数据结构转换为以下表达式: $result = lookup('x') || lookup('y') && lookup('z') || lookup

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

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;

我只是想再多看一眼,以确保上面的内容是有意义的——我已经运行了很多次这个算法,但似乎有几次它没有返回正确的布尔值。

大声说出来几乎让人害怕,但是你发现了一个罕见的例子,它实际上是一个有效的解决方案,而不是一个问题本身。只需将您的输入“编译”到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
可能就足够了

实际上,使用
查找
功能,它变得更加简单:

$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);

这是完全安全的,而且比你能想到的任何其他方法都要短。

大声说出来几乎让人害怕,但你发现了一种罕见的情况,它实际上是一个有效的解决方案,而不是一个问题本身。只需将您的输入“编译”到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
可能就足够了

实际上,使用
查找
功能,它变得更加简单:

$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);

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

你试图实现的被称为。这尤其用于制作编译器和解释器。这是一种针对您的问题类型的实用表示法,因为它可以处理运算符优先级,而您的平面表示法使其变得困难

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

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);

您试图实现的称为。这尤其用于制作编译器和解释器。这是一种针对您的问题类型的实用表示法,因为它可以处理运算符优先级,而您的平面表示法使其变得困难

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

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);

在哪种语言中v比z更重要?在哪种语言中v比z更重要?因此我给出的示例的计算结果为
true
。尽管如此,这一点一直被认为是正确的。对于我的特定应用程序,我对分组或优先级不感兴趣,只是为了得到布尔表达式的整体结果。我知道这些运算符的优先级,我只是编了一些示例,但没有100%准确地回答您的问题:),因此我给出的示例将评估为
true
。尽管如此,这一点一直被认为是正确的。对于我的特定应用程序,我对分组或优先级不感兴趣,只是为了得到布尔表达式的整体结果。我知道这些运算符的优先级,我只是编了一些示例,但没有100%准确地回答您的问题:)