<?php
$conditions = 'C++ AND ((UML OR Python) OR (not Perl))' ;
// Other tests...
//$conditions = "C++ AND Python OR Perl";
//$conditions = "C++ AND Python OR Perl OR (Perl AND (Ruby AND Docker AND (Lisp OR (C++ AND Ada) AND Java)))";
///////// CONFIGURATION /////////
$maxNest = 0 ; // Set to 0 for unlimited nest levels
/////////////////////////////////
print "Original Input:\n " ;
print $conditions . "\n \n " ;
// Add implicit parenthesis...
// For example: `A AND B OR C` should be: `(A AND B) OR C`
$addParenthesis = '/(?|(((?:\bNOT\b\s*+)?+[^)(\s]++|(?:\bNOT\b\s*+)?+[(](?:\s*+(?2)\s*+)*+[)])(?:\s*+\bAND\b\s*+((?2)))++)(?=\s*+\bOR\b\s*+)|\s*+\bOR\b\s*+\K((?1)))/im' ;
while ( preg_match ( $addParenthesis , $conditions ) ) { $conditions = preg_replace ( $addParenthesis , '(\1)' , $conditions ) ; }
print "Input after adding implicit parenthesis (if needed):\n " ;
print $conditions . "\n \n " ;
// Optional cleanup: Remove useless NOT () parenthesis
$conditions = preg_replace ( '/[(]\s*((?:NOT\s*)?+(\S+))\s*[)]/i' , '\1' , $conditions ) ;
// Optional cleanup: Remove useless NOT NOT...
$conditions = preg_replace ( '/\bNOT\s+NOT\b/i' , '' , $conditions ) ;
$list_conditions = [ $conditions ] ;
function split_conditions( $input , $level = 0 ) {
global $list_conditions , $maxNest ;
if ( $maxNest > 0 && $level >= $maxNest ) { return ; }
// If it is a logic operator, skip
if ( preg_match ( '/^\s*(?:AND|OR)\s*$/i' , $input ) ) { return ;
}
// Add condition to the list:
// Don't go on if this is a single filter
if ( preg_match ( '/^\s*(?:NOT\s+)?+[^)(\s]+\s*$/i' , $input ) ) { return ;
}
// Remove parenthesis (if exists) before evaluating sub expressions
// Do this only for level > 0. Level 0 is not guaranteed to have
// sorrounding parenthesis, so It may remove wanted parenthesis
// such in this expression: `(Cond1 AND Cond2) OR (Cond3 AND Cond4)`
if ( $level > 0 ) {
$input = preg_replace ( '/^\s*(?:NOT\b\s*)?+[(](.*)[)]\s*$/i' , '\1' , $input ) ; }
// Fetch all sub-conditions at current level:
$next_conds = '/((?:\bNOT\b\s*+)?+[^)(\s]++|(?:\bNOT\b\s*+)?+[(](?:\s*+(?1)\s*+)*+[)])/i' ;
// Evaluate subexpressions
foreach ( $matches [ 0 ] as $match ) {
split_conditions( $match , $level + 1 ) ;
}
}
split_conditions( $conditions ) ;
// Trim and remove duplicates
} , $list_conditions ) ) ;
// Add columns
return preg_replace ( '/([^\s()]++)(?<!\bAND\b)(?<!\bOR\b)(?<!\bNOT\b)/i' , "skill='$1 '" , $x ) ; } , $list_conditions ) ;
print "Just the conditions...\n \n " ;
print "\n \n " ;
print "Method 1) Single query with multiple SUM\n \n " ;
return " SUM( $x )" ;
} , $list_conditions ) ) ;
$sumSQL = "SELECT\n $sum_conditions \n FROM candidates;" ;
print $sumSQL . "\n \n " ;
print "Method 2) Multiple queries\n \n " ;
return "SELECT count(*) from candidates WHERE $x ;" ;
} , $list_conditions ) ) ;
print $queries . "\n \n " ;
PD9waHAKCiRjb25kaXRpb25zID0gJ0MrKyBBTkQgKChVTUwgT1IgUHl0aG9uKSBPUiAobm90IFBlcmwpKSc7CgovLyBPdGhlciB0ZXN0cy4uLgovLyRjb25kaXRpb25zID0gIkMrKyBBTkQgUHl0aG9uIE9SIFBlcmwiOwovLyRjb25kaXRpb25zID0gIkMrKyBBTkQgUHl0aG9uIE9SIFBlcmwgT1IgKFBlcmwgQU5EIChSdWJ5IEFORCBEb2NrZXIgQU5EIChMaXNwIE9SIChDKysgQU5EIEFkYSkgQU5EIEphdmEpKSkiOwoKLy8vLy8vLy8vIENPTkZJR1VSQVRJT04gLy8vLy8vLy8vCiRtYXhOZXN0ID0gMDsgLy8gU2V0IHRvIDAgZm9yIHVubGltaXRlZCBuZXN0IGxldmVscwovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCnByaW50ICJPcmlnaW5hbCBJbnB1dDpcbiI7CnByaW50ICRjb25kaXRpb25zIC4gIlxuXG4iOwoKLy8gQWRkIGltcGxpY2l0IHBhcmVudGhlc2lzLi4uCi8vIEZvciBleGFtcGxlOiBgQSBBTkQgQiBPUiBDYCBzaG91bGQgYmU6IGAoQSBBTkQgQikgT1IgQ2AKJGFkZFBhcmVudGhlc2lzID0gJy8oP3woKCg/OlxiTk9UXGJccyorKT8rW14pKFxzXSsrfCg/OlxiTk9UXGJccyorKT8rWyhdKD86XHMqKyg/MilccyorKSorWyldKSg/OlxzKitcYkFORFxiXHMqKygoPzIpKSkrKykoPz1ccyorXGJPUlxiXHMqKyl8XHMqK1xiT1JcYlxzKitcSygoPzEpKSkvaW0nOwp3aGlsZSAocHJlZ19tYXRjaCgkYWRkUGFyZW50aGVzaXMsICRjb25kaXRpb25zKSkgewogICRjb25kaXRpb25zID0gcHJlZ19yZXBsYWNlKCRhZGRQYXJlbnRoZXNpcywgJyhcMSknLCAkY29uZGl0aW9ucyk7Cn0KCnByaW50ICJJbnB1dCBhZnRlciBhZGRpbmcgaW1wbGljaXQgcGFyZW50aGVzaXMgKGlmIG5lZWRlZCk6XG4iOwpwcmludCAkY29uZGl0aW9ucyAuICJcblxuIjsKCi8vIE9wdGlvbmFsIGNsZWFudXA6IFJlbW92ZSB1c2VsZXNzIE5PVCAoKSBwYXJlbnRoZXNpcwokY29uZGl0aW9ucyA9IHByZWdfcmVwbGFjZSgnL1soXVxzKigoPzpOT1RccyopPysoXFMrKSlccypbKV0vaScsICdcMScsICRjb25kaXRpb25zKTsKCi8vIE9wdGlvbmFsIGNsZWFudXA6IFJlbW92ZSB1c2VsZXNzIE5PVCBOT1QuLi4KJGNvbmRpdGlvbnMgPSBwcmVnX3JlcGxhY2UoJy9cYk5PVFxzK05PVFxiL2knLCAnJywgJGNvbmRpdGlvbnMpOwoKJGxpc3RfY29uZGl0aW9ucyA9IFskY29uZGl0aW9uc107CgpmdW5jdGlvbiBzcGxpdF9jb25kaXRpb25zKCRpbnB1dCwgJGxldmVsID0gMCkgewogIGdsb2JhbCAkbGlzdF9jb25kaXRpb25zLCAkbWF4TmVzdDsKICAKICBpZiAoJG1heE5lc3QgPiAwICYmICRsZXZlbCA+PSAkbWF4TmVzdCkgeyByZXR1cm47IH0KICAKICAvLyBJZiBpdCBpcyBhIGxvZ2ljIG9wZXJhdG9yLCBza2lwCiAgaWYgKCBwcmVnX21hdGNoKCcvXlxzKig/OkFORHxPUilccyokL2knLCAkaW5wdXQpICkgewogICAgcmV0dXJuOwogIH0KICAKICAvLyBBZGQgY29uZGl0aW9uIHRvIHRoZSBsaXN0OgogIGFycmF5X3B1c2goJGxpc3RfY29uZGl0aW9ucywgJGlucHV0KTsKICAKICAvLyBEb24ndCBnbyBvbiBpZiB0aGlzIGlzIGEgc2luZ2xlIGZpbHRlcgogIGlmICggcHJlZ19tYXRjaCgnL15ccyooPzpOT1RccyspPytbXikoXHNdK1xzKiQvaScsICRpbnB1dCkgKSB7CiAgICByZXR1cm47CiAgfQoKICAvLyBSZW1vdmUgcGFyZW50aGVzaXMgKGlmIGV4aXN0cykgYmVmb3JlIGV2YWx1YXRpbmcgc3ViIGV4cHJlc3Npb25zCiAgLy8gRG8gdGhpcyBvbmx5IGZvciBsZXZlbCA+IDAuIExldmVsIDAgaXMgbm90IGd1YXJhbnRlZWQgdG8gaGF2ZQogIC8vIHNvcnJvdW5kaW5nIHBhcmVudGhlc2lzLCBzbyBJdCBtYXkgcmVtb3ZlIHdhbnRlZCBwYXJlbnRoZXNpcyAKICAvLyBzdWNoIGluIHRoaXMgZXhwcmVzc2lvbjogYChDb25kMSBBTkQgQ29uZDIpIE9SIChDb25kMyBBTkQgQ29uZDQpYAogIGlmICgkbGV2ZWwgPiAwKSB7CiAgICAkaW5wdXQgPSBwcmVnX3JlcGxhY2UoJy9eXHMqKD86Tk9UXGJccyopPytbKF0oLiopWyldXHMqJC9pJywgJ1wxJywgJGlucHV0KTsKICB9CgogIC8vIEZldGNoIGFsbCBzdWItY29uZGl0aW9ucyBhdCBjdXJyZW50IGxldmVsOgogICRuZXh0X2NvbmRzID0gJy8oKD86XGJOT1RcYlxzKispPytbXikoXHNdKyt8KD86XGJOT1RcYlxzKispPytbKF0oPzpccyorKD8xKVxzKispKitbKV0pL2knOwogIHByZWdfbWF0Y2hfYWxsKCRuZXh0X2NvbmRzLCAkaW5wdXQsICRtYXRjaGVzKTsKCiAgLy8gRXZhbHVhdGUgc3ViZXhwcmVzc2lvbnMKICBmb3JlYWNoICgkbWF0Y2hlc1swXSBhcyAkbWF0Y2gpIHsKICAgIHNwbGl0X2NvbmRpdGlvbnMoJG1hdGNoLCAkbGV2ZWwgKyAxKTsKICB9Cn0KCnNwbGl0X2NvbmRpdGlvbnMoJGNvbmRpdGlvbnMpOwoKLy8gVHJpbSBhbmQgcmVtb3ZlIGR1cGxpY2F0ZXMKJGxpc3RfY29uZGl0aW9ucyA9IGFycmF5X3VuaXF1ZShhcnJheV9tYXAoZnVuY3Rpb24oJHgpewogIHJldHVybiBwcmVnX3JlcGxhY2UoJy9eXHMqfFxzKiQvJywgJycsICR4KTsKfSwgJGxpc3RfY29uZGl0aW9ucykpOwoKLy8gQWRkIGNvbHVtbnMKJGxpc3RfY29uZGl0aW9ucyA9IGFycmF5X21hcChmdW5jdGlvbigkeCl7CiAgcmV0dXJuIHByZWdfcmVwbGFjZSgnLyhbXlxzKCldKyspKD88IVxiQU5EXGIpKD88IVxiT1JcYikoPzwhXGJOT1RcYikvaScsICJza2lsbD0nJDEnIiwgJHgpOwp9LCAkbGlzdF9jb25kaXRpb25zKTsKCnByaW50ICJKdXN0IHRoZSBjb25kaXRpb25zLi4uXG5cbiI7CnByaW50X3IoJGxpc3RfY29uZGl0aW9ucyk7CnByaW50ICJcblxuIjsKCnByaW50ICJNZXRob2QgMSkgU2luZ2xlIHF1ZXJ5IHdpdGggbXVsdGlwbGUgU1VNXG5cbiI7CiRzdW1fY29uZGl0aW9ucyA9IGltcGxvZGUoIixcbiIsIGFycmF5X21hcChmdW5jdGlvbigkeCl7CiAgcmV0dXJuICIgICAgU1VNKCAkeCApIjsKfSwgJGxpc3RfY29uZGl0aW9ucykpOwokc3VtU1FMID0gIlNFTEVDVFxuJHN1bV9jb25kaXRpb25zXG5GUk9NIGNhbmRpZGF0ZXM7IjsKcHJpbnQgJHN1bVNRTCAuICJcblxuIjsKCnByaW50ICJNZXRob2QgMikgTXVsdGlwbGUgcXVlcmllc1xuXG4iOwokcXVlcmllcyA9IGltcGxvZGUoIlxuIiwgYXJyYXlfbWFwKGZ1bmN0aW9uKCR4KXsKICByZXR1cm4gIlNFTEVDVCBjb3VudCgqKSBmcm9tIGNhbmRpZGF0ZXMgV0hFUkUgJHg7IjsKfSwgJGxpc3RfY29uZGl0aW9ucykpOwpwcmludCAkcXVlcmllcyAuICJcblxuIjsK