I would like to take a and/or logic query query string of unknown length:
$logic = 'elephants and tigers or dolphins and apes or monkeys and humans and gorillas and and 133322 or 2';
And parse it into an array, I assume would look something like:
$parsed_to_or = array(
array('elephants', 'tigers'),
array('dolphins', 'apes'),
array('monkeys', 'humans', 'gorillas', '133322'),
array('2')
);
This is what I have so far:
$logic_e = preg_split('/\s+/', $logic);
$or_segments = array();
$and_group = array();
foreach($logic_e as $fragment) {
if (preg_match('/^(and|&&)$/i', $fragment)) {
continue;
} elseif (preg_match('/^(or|\\|\\|)$/i', $fragment)) {
if (count($and_group)>0) {
$or_segments[] = $and_group;
$and_group = array();
} continue;
} else {
$and_group[] = $fragment;
continue;
}
}
if (count($and_group)>0) {
$or_segments[] = $and_group;
$and_group = array();
}
Any better ways to tackle this?
Update: Added the ability to use && and || anywhere
You can do the following:
<?php
$logic = 'elephants && tigers || dolphins && apes || monkeys and humans and gorillas and && 133322 or 2';
$result = array();
foreach (preg_split('/ (or|\|\|) /', $logic) as $parts) {
$bits = preg_split('/ (and|&&) /', $parts);
for ($x=0; $x<count($bits); $x++) {
$bits[$x] = preg_replace('/\s?(and|&&)\s?/', '', $bits[$x]);
}
$result[] = $bits;
}
echo '<pre>';
var_dump($result);
Which would result in the following:
array(4) {
[0]=>
array(2) {
[0]=>
string(9) "elephants"
[1]=>
string(6) "tigers"
}
[1]=>
array(2) {
[0]=>
string(8) "dolphins"
[1]=>
string(4) "apes"
}
[2]=>
array(4) {
[0]=>
string(7) "monkeys"
[1]=>
string(6) "humans"
[2]=>
string(8) "gorillas"
[3]=>
string(6) "133322"
}
[3]=>
array(1) {
[0]=>
string(1) "2"
}
}
How about this:
$logic = 'elephants and tigers or dolphins and apes or monkeys and humans and gorillas and and 133322 or 2';
$ors = preg_split('/(\bor\b|\s\|\|\s)/', $logic);
foreach ($ors as &$or) {
$or = array_filter(array_map('trim', preg_split('/(\band\b|\s&&\s)/', $or)));
}
var_dump($ors);
Using explode
is much more simple:
$logic = 'elephants and tigers or dolphins and apes or monkeys and humans and gorillas and and 133322 or 2';
$parts = explode(" or ", $logic);
foreach($parts as $part){
if(!empty($part)){
$finalArray[] = explode(" and ", $part);
}
}
print_r($finalArray);
That would return:
Array
(
[0] => Array
(
[0] => elephants
[1] => tigers
)
[1] => Array
(
[0] => dolphins
[1] => apes
)
[2] => Array
(
[0] => monkeys
[1] => humans
[2] => gorillas
[3] => and 133322
)
[3] => Array
(
[0] => 2
)
)
This will handle the gorillas
problem, and the empty entries such as and and
$logic = 'elephants and tigers or dolphins and apes || monkeys and humans and gorillas and and 133322 or 2';
$arrayBlocks = preg_split('/(\bor\b|\|\|)/', $logic);
array_walk(
$arrayBlocks,
function(&$entry, $key) {
$entry = preg_split('/(\band\b|&&)/', $entry);
$entry = array_filter(
array_map(
'trim',
$entry
)
);
}
);
var_dump($arrayBlocks);
though array_filter will also clean a 0
entry
What I'm thinking I'll go with:
$or_segments = array();
foreach(preg_split('/((\\s+or\\s+|\\s*\\|\\|\\s*))+/i', $logic) as $or_split_f) {
$or_segments[] = preg_split('/((\\s+and\\s+|\\s*&&\\s*))+/i', $or_split_f);
}
var_dump($or_segments);