Php 布尔表达式:多个中缀字符串的后缀
给定以下(中缀)表达式:Php 布尔表达式:多个中缀字符串的后缀,php,algorithm,postfix-notation,infix-notation,shunting-yard,Php,Algorithm,Postfix Notation,Infix Notation,Shunting Yard,给定以下(中缀)表达式: (country = be or country = nl) and (language = en or language = nl) and message contains twitter 我想创建以下4个中缀符号: message contains twitter and country = be and language = en message contains twitter and country = be and language = en mes
(country = be or country = nl) and
(language = en or language = nl) and
message contains twitter
我想创建以下4个中缀符号:
message contains twitter and country = be and language = en
message contains twitter and country = be and language = en
message contains twitter and country = nl and language = nl
message contains twitter and country = nl and language = nl
所以,基本上,我想去掉所有的OR
我已经有了第一个表达式的后缀符号,所以我正在尝试处理它以获得所需的符号。然而,这种特殊情况会带来麻烦
(为了便于说明,此查询的后缀符号为:)
有人知道实现这一点的算法吗?将问题分为两个步骤:后缀到多个后缀,后缀到中缀。每个步骤都是通过“解释”后缀表达式来执行的 对于多后缀解释器的后缀:堆栈值是后缀表达式的集合。解释规则如下
<predicate>: push a one-element collection containing <predicate>.
AND: pop the top two collections into C1 and C2. With two nested loops,
create a collection containing x y AND for all x in C1 and y in C2.
Push this collection.
OR: pop the top two collections into C1 and C2. Push the union of C1 and C2.
:推送包含的单元素集合。
和:将前两个集合分为C1和C2。有两个嵌套循环,
为C1中的所有x和C2中的y创建一个包含x和y的集合。
推送此集合。
或者:将前两个集合弹出到C1和C2中。推动C1和C2的接头。
对于后缀到中缀解释器:堆栈值是中缀表达式
<predicate>: push <predicate>.
AND: pop two expressions into x and y. Push the expression (x) and (y).
:推送。
和:将两个表达式弹出到x和y中。按下表达式(x)和(y)。
这些步骤可以组合在一起,但我想给出两个这种技术的示例。使用树表示可能是最简单的。使用调车场算法建立一个表示方程式的二叉树。树中的节点可能是:
class Node {
const OP = 'operator';
const LEAF = 'leaf';
$type = null; // Will be eight Node::OP or Node::LEAF
$op = null; // could be 'or' or 'and' 'contains';
$value = null; // used for leaf eg 'twitter'
$left = null;
$right = null;
}
尽管可以使用子类。在调车场算法中,您希望更改输出步骤以生成树
一旦有了树表示,就需要几种算法
首先,您需要一个复制树的算法
public function copy($node) {
if($node->type == Node::LEAF) {
$node2 = new Node();
$node2->type = Node::LEAF;
$node2->value = $node->value;
return $node2;
}
else {
$left = copy($node->left);
$right = copy($node->right);
$node2 = new Node();
$node2->type = Node::OP;
$node2->op = $node->op;
$node2->left = $node->left;
$node2->right = $node->right;
return $node2;
}
}
接下来是查找第一个“或”操作符节点的算法
function findOr($node) {
if($node->type == Node::OP && $node->op == 'or') {
return $node;
} else if($node->type == Node::OP ) {
$leftRes = findOr($node->$left);
if( is_null($leftRes) ) {
$rightRes = findOr($node->$right); // will be null or a found node
return $rightRes;
} else {
return $leftRes; // found one on the left, no need to walk rest of tree
}
} else {
return null;
}
}
最后一个算法copyLR给出左(真)或右(假)分支。除非在返回左分支或右分支时节点与$target匹配,否则它的行为与copy相同
public function copyLR($node,$target,$leftRight) {
if($node == $target) {
if($leftRight)
return copy($node->left);
else
return copy($node->right);
}
else if($node->type == Node::LEAF) {
$node2 = new Node();
$node2->type = Node::LEAF;
$node2->value = $node->value;
return $node2;
}
else {
$left = copy($node->left,$target,$leftRight);
$right = copy($node->right,$target,$leftRight);
$node2 = new Node();
$node2->type = Node::OP;
$node2->op = $node->op;
$node2->left = $node->left;
$node2->right = $node->right;
return $node2;
}
}
这些碎片现在已经拼在一起了
$root = parse(); // result from the parsing step
$queue = array($root);
$output = array();
while( count($queue) > 0) {
$base = array_shift($queue);
$target = findOr($base);
if(is_null($target)) {
$output[] = $base; // no or operators found so output
} else {
// an 'or' operator found
$left = copyLR($base,$target,true); // copy the left
$right = copyLR($base,$target,false); // copy the right
array_push($left); // push both onto the end of the queue
array_push($right);
}
}
$root = parse(); // result from the parsing step
$queue = array($root);
$output = array();
while( count($queue) > 0) {
$base = array_shift($queue);
$target = findOr($base);
if(is_null($target)) {
$output[] = $base; // no or operators found so output
} else {
// an 'or' operator found
$left = copyLR($base,$target,true); // copy the left
$right = copyLR($base,$target,false); // copy the right
array_push($left); // push both onto the end of the queue
array_push($right);
}
}