Evaluate a boolean condition stored as a string - javascript

I have several thousand entries in a database that were scraped from a website. They are strings which list conditions which must be met. For example: "(Thing1 and Thing2) or (Thing3 and Thing4)"
I would like a user to enter a list of conditions they have, and then check them against the database. Due to the fact that these strings come from a trusted site, and are so close to valid boolean conditions already I'm tempted to put them in an eval() statement. I could parse the string, find the conditions, check if they are true, and replace them with 1 or 0. Then replace (and, or) with (&&, ||). Then I would check to make sure everything at that point is one of: space, 1, 0, &, |, (, or ). If not, log the error in some way. If it is just those characters do:
eval("Boolean((1 && 0) || (0 && 0))")
I realize eval() is generally a bad idea, so I'm open to other ideas. However, in this case I feel the security is increased if I check for just those characters before running the eval, and since the input is data scraped from a trusted site.
I'm planning on doing this in javascript, but could also do it in PHP on the server.

If you really want to avoid eval() at all cost, you could use something like this:
function evalBoolean(str) {
while (str.length > 1) {
str = str.replace(/0 && 0|0 && 1|1 && 0|0 \|\| 0|\(0\)/g, "0");
str = str.replace(/1 && 1|0 \|\| 1|1 \|\| 0|1 \|\| 1|\(1\)/g, "1");
}
return (str == "1");
}
alert(evalBoolean("((0 && 1) || (1 && 1))"));
alert(evalBoolean("(((0 || 1) && (0 || 0)) && ((1 || 1) || 0))"));
If you think there could be malformed input, use this safer version which returns undefined if it can't resolve the expression.
function evalBoolean(str) {
var len;
while (str.length > 1) {
if (str.length == len) return; else len = str.length;
str = str.replace(/0\s*&&\s*0|0\s*&&\s*1|1\s*&&\s*0|0\s*\|\|\s*0|\(\s*0\s*\)|\s*0\s*/g, "0");
str = str.replace(/1\s*&&\s*1|0\s*\|\|\s*1|1\s*\|\|\s*0|1\s*\|\|\s*1|\(\s*1\s*\)|\s*1\s*/g, "1");
}
return (str == "1");
}
alert(evalBoolean(" (( (0|| 1) &&(0 || 0) )&& ( (1||1) ||0))"));
alert(evalBoolean("((1 && 0) && 1 )) ( && 1"));

Related

Checking whether ANY url is true

I am new to Javascript as well as Jquery , but can not figure out what I am doing wrong. I just want to check if the user is on any of 3 URLs. I just want to check if the user is on either the ABOUT US, MEMSTAFF TEAM or CAREERS sections. That is it. I thought that if I just used the OR (||) operator, this should work. What am I doing wrong?
<script type="text/javascript">
$(document).ready(function() {
// Check if any of these relative URLS are true
if(window.location.href.indexOf("/about-us" || "/memstaff-team" || "/careers") > -1) {
// Alert me if I am in one of the MAIN sections
alert("Your are in one of the MAIN sections");
}
});
</script>
The test
if (window.location.href.indexOf("/about-us" || "/memstaff-team" || "/careers") > -1)
is equivalent to doing
temp = "/about-us" || "/memstaff-team" || "/careers";
if (window.location.href.indexOf(temp) > -1)
Since the || operator just returns the first truthy value, it's effectively doing temp = "/about-us" and just testing for that. "OR" expressions aren't automatically distributed, you need to do it explicitly.
if (window.location.href.indexOf("/about-us") > -1 ||
window.location.href.indexOf("/memstaff-team") > -1 ||
window.location.href.indexOf("/careers") > -1)
But a simpler way is to use a regular expression:
if (window.location.href.match(/\/(about-us|memstaff-team|careers)/))
Here is another way of doing it:
const urls = ["/about-us", "/memstaff-team", "/careers"];
if (urls.some(url => window.location.href.indexOf(url) > -1)) {
alert("...");
}

Need help understanding this lisp function

I am having trouble understanding the return line in this function.
I'm creating a parser in C# and found this tutorial (http://lisperator.net/pltut/parser/the-parser) which was written in Javascript. I can't understand the return line of the function
function is_punc(ch) {
var tok = input.peek();
return tok && tok.type == "punc" && (!ch || tok.value == ch) && tok;
}
I believe it will return true if: tok is not null AND its type is punc AND (the char ch is not null OR the value of tok equals ch) AND tok is not null.
If I am reading this right why is he evaluating tok is not null twice.
It's not meaningful in this context, but the logical operators in JavaScript work like those in Python and Lisp (the only connection to Lisp in this question).
That is, a && b returns a if it is "false-y", otherwise it returns b.
Similarly, a || b returns a if it is "truth-y", otherwise it returns b.
Examples (from my Firefox console):
> "" && 23
< ""
> 0 && 23
< 0
> 1 && 23
< 23
> 1 && "hello"
< "hello"
> "hello" || "world"
< "hello"
> 0 || "world"
< "world"
This means that the final tok makes the function return the token itself if all the other conditions are truth-y.
You can express boolean logic with more than true/false, and some languages exploit this to return more information from boolean operators. For example, in a JS console, you can write the following:
> x = 10
10
> (x < 100) && x
10
An integer like 10 belongs to the set of True values when used in a boolean context. The result is thus 10.
The same happens in Lisp, where (or (try-first-this) (maybe-that)) evaluates to the first expression that holds true.
In your case the last term is necessary for the function to return the token.

function not executing on comparison of two arrays

I am trying to get a comparison operator to work, without success. The operator compares two arrays to ensure they are identical.
if (($(array_1).not($(array_2)).length === 0 && $(array_2).not($(array_1)).length === 0)) {
alert("all matches dropped");
}
The code works of course with 'true' in place of the comparison.
if (true) {
alert("all matches dropped");
}
The strange part is that the comparison returns 'true' when entered into the console:
console.log($(array_1).not($(array_2)).length === 0 && $(array_2).not($(array_1)).length === 0)
----> true
Any ideas what may be wrong? Thanks.
It should be:
if($(array_1).not(array_2).length === 0 && $(array_2).not(array_1).length === 0)
Instead of:
if (($(array_1).not($(array_2)).length === 0 && $(array_2).not($(array_1)).length === 0))
Here $(array_1).not(array_2).length and ($(array_1).not($(array_2)).length both are not the same thing.

Javascript (-1 <= 5 <= 1) === true?

I want to validate that a given number is within a given range:
function validate(min, max, amount) {
return (min <= amount <= max);
}
But this does not seem to work properly. I know I can do it with two comparison and a logical AND, but I would like to it in one comparison. Is there any NATIVE javascript way to realize this?
Use this instead :
return (min <= amount && amount <= max);
There is no shortcut. And there is a good reason the JavaScript engine can't guess your intent : what you typed was valid, it just isn't interpreted as you'd like. You were testing, in fact
((min <= amount) <= max)
and the result of the first comparison, which is a boolean, is converted to 0 or 1 for the second one (more details here about operators precedence, those comparison operators are left-to-right).
If you really want a shortcut, you could do this :
Number.prototype.isin = function(m,M) {
return m<=this && this<=M;
};
console.log(0.5.isin(1,2)); // logs false
console.log(3..isin(2,5)); // logs true
but I personally would use the standard solution with && that everybody can read and which doesn't involve an additional function call.
Aside : I could have called my function in instead of isin but it might break ES3 browsers.
Operators ( == , <= , < , >= , == ) take only 2 arguments.
When there are more arguments it uses mathematical order of computing. So in fact your code behave like:
min <= amount // true
true <= max // this is illogical
It's also optimal, because when executing logical statements and finding something like:
if(false && (some computing))
It will ignore (some computing) because result will be always false
This is very common practive in every language. Test like this will not have NullPointerException error, because first argument is already false.
if(obj != null && obj.getValue() > 10) //C++,Java, etc.
if(obj !== undefined && obj.val() > 10) // javascript
if(obj.length != 0 && obj.val() > 10) //jQuery

Can't make multiple if conditions in JavaScript?

I have absolutely no idea why this is not working. Makes no sense to me.
This returns a "syntax error: parse error":
if ($(this).attr("id") === 'search' || opening = true) return false;
For good measure, I also tried the following, which yielded the same result:
if (1 = 1 && 2 = 2) { return false; }
There are three different operators at play:
=: assignment
==: equality
===: strict equality
= actually modifies a variable, so you shouldn't use it inside if statements. That is, you should use ... || opening == true) instead of ... || opening = true).
In JavaScript = is used to assign values, while == and === are used to compare them.
When you put opening = true in your if statement, you aren't checking if opening is true, you are setting opening to true. Try using == instead.
For example,
var x = 5;
if (x == 10) {
alert("x is 10");
} else {
alert("x isn't 10");
}
will display "x isn't 10", while
var x = 5;
if (x = 10) {
alert("x is 10");
} else {
alert("x isn't 10");
}
will display "x is 10".
the first example should read:
if ($(this).attr("id") === 'search' || opening == true) return false;
and the second:
if (1 == 1 && 2 == 2) { return false; }
Note the double equals (==) sign for logic equals is not the same as the single equals (=) sign, that handles variable assignment.
You have an error in your condition
if ($(this).attr("id") === 'search' || opening = true) return false;
should be
if ($(this).attr("id") === 'search' || opening == true) return false;
the problem is with the equals sign
= is different to ==
the first one is the assignment operator. the second one is for comparison
When you test like this:
opening=true;
What you are really doing is setting opening to the value of true. Use == instead.
Finally, order of operations, even if correct, can get confusing. Put parenthesis around each part of the comparison.
if (($(this).attr("id") === 'search') || (opening == true)) return false;
My guess is that === does not exist.
== is for testing equality
so if ($(this).attr("id") === 'search' || opening == true) return false;
should be if ($(this).attr("id") == 'search' || opening == true) return false;

Categories