I have an array like this:
[true, "&&", false]
The true and false statements are generated by previous conditions and pushed onto an array (i'm trying to provide users with a way to create basic logic themselves within my web project).
What I can't figure out is how to turn this array into an actual if statement that runs like this:
if(true && false) {
// Run Code
}
Note that depending on what the user setup the array could look like this:
[true, "||", false]
if(true || false) {
// Run code
}
I want to allow the array to also allow parentheses:
["(", true, "&&", false, ")", "||", true]
should become:
if( (true && false) || true) {
// RUN CODE
}
You could, although it's evil, use an eval after joining all the array elements. i.e.
var arr = [true, '&&', false];
if(eval(arr.join(''))){
// your code
}
Update:
I just recently thought of a much simple (not simpler than eval) but safe answer. If the only boolean operations you're using are &&
and ||
and the parentheses are properly formatted, then you could do a bunch of regex replaces until there is only one value left, either "true" or "false".
The boolean values for AND operations can only be as follows and they simplify to either true or false
true && true == true
true && false == false
false && true == false
false && false == false
the same goes for OR operations
true || true == true
true || false == true
false || true == true
false || false == false
As a result, we can replace the expression with their simplified values - true or false. Then, if there are parentheses around the expression it'll end up as either '(true)'
or '(false)'
and we can easily regex replace that as well.
We can then loop this routine until we're finally left with one value, either 'true'
or 'false'
.
i.e. in code
var boolArr = ["(", true, "&&", "(", false, "||", true, ")", ")", "||", true];
//Convert the array to a string "(true&&(false||true))||true"
var boolString = boolArr.join('');
//Loop while the boolean string isn't either "true" or "false"
while(!(boolString == "true" || boolString == "false")){
//Replace all AND operations with their simpler versions
boolString = boolString.replace(/true&&true/g,'true').replace(/true&&false/g,'false');
boolString = boolString.replace(/false&&true/g,'false').replace(/false&&false/g,'false');
//Replace all OR operations with their simpler versions
boolString = boolString.replace(/true\|\|true/g,'true').replace(/true\|\|false/g,'true');
boolString = boolString.replace(/false\|\|true/g,'true').replace(/false\|\|false/g,'false');
//Replace '(true)' and '(false)' with 'true' and 'false' respectively
boolString = boolString.replace(/\(true\)/g,'true').replace(/\(false\)/g,'false');
}
//Since the final value is a string of "true" or "false", we must convert it to a boolean
value = (boolString == "true"?true:false);
Annd, if you're really dangerous, you can chain all those replaces together
Also, please notice the lovely lack of recursion and use of only one loop
Another solution with building of a nested array if parentheses exist and with an object for the operations, which could be easily extended.
How it works:
The term array is iterated and a new array is build upon. For every new opening parentheses, an empty array is assigned to the next level. All next terms are now pushed to the next level.
If a closing parentheses is found, the actual level is summarized with
calculate
and the result is pushed to the next lower level.At the end, the base level is pooled and the result returned.
For evaluation, an object with functions for binary function symbols is used.
function process(logic) {
function calculate(a) {
while (a.length > 2) {
a.splice(0, 3, op[a[1]](a[0], a[2]));
}
return a[0];
}
var op = {
'&&': function (a, b) { return a && b; },
'||': function (a, b) { return a || b; }
},
array = [[]],
level = 0;
logic.forEach(function (a) {
if (a === '(') {
++level;
array[level] = [];
return;
}
if (a === ')') {
--level;
array[level].push(calculate(array[level + 1]));
return;
}
array[level].push(a);
});
return calculate(array[0]);
}
function print(logic) {
document.write(logic.join(' ') + ': <strong>' + process(logic) + '</strong><br>');
}
print([true, "&&", false]); //false
print([true, "&&", true]); //true
print([false, "||", true]); //true
print([false, "||", false]); //false
print(["(", true, "&&", false, ")", "||", true]); //true
print(["(", true, "&&", "(", false, "||", true, ")", ")", "||", true]); //true
print([false, "||", "(", "(", true, "&&", "(", false, "||", true, ")", ")", "&&", false, ")"]); //false
What you want is a recursive descent parser.
The following code will handle true
, false
, &&
, and ||
, along with parentheses (which may be nested).
You can easily add other binary operators as needed.
function process(logic) {
var result, op, i, par, idx, token;
for(i = 0; i < logic.length; i++) {
token = logic[i];
if(token === '&&' || token === '||') {
op = token;
}
else {
if(token === '(') {
for(par = 0, idx = i ; par ; idx++) { //handle nested parentheses
if (logic[idx] === '(') par++;
else if(logic[idx] === ')') par--;
}
token = process(logic.slice(i + 1, idx));
i = idx + 1;
}
if (op === '&&') result = result && token;
else if(op === '||') result = result || token;
else result = token;
}
};
return result;
} //process
function print(logic) {
console.log(logic.join(' ') + ': ' + process(logic));
}
print([true, "&&", false]); //false
print([true, "&&", true]); //true
print([false, "||", true]); //true
print([false, "||", false]); //false
print(["(", true, "&&", false, ")", "||", true]); //true
print(["(", true, "&&", "(", false, "||", true, ")", ")", "||", true]); //true
print([false, "||", "(", "(", true, "&&", "(", false, "||", true, ")", ")", "&&", false, ")"]); //false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With