javascript OR (||) not returning expected result - javascript

I have a field that needs to accept input values for city/state in several formats, including City ST (Chicago IL), City, ST (Chicago, IL), and City,ST (Chicago,IL - no space between). We're testing for a two-letter state code after either a comma or the last instance of a space (because city names can have spaces.)
I have the following code that fails values that should pass, and vice versa.
var x = "Chicago,IL";
if (
(isNaN(x) && x.indexOf(' ') < 0 && x.split(" ").pop().length > 2) ||
(isNaN(x) && x.indexOf(',') > 0 && x.split(",").pop().trim().length > 2)
) {
alert("fail");
}
else {
alert("pass");
}
(Fiddle here)
So what my code SHOULD do is fail if 1) the value is not a number AND contains at least one space AND there are more than 2 characters after the final space, or 2) the value is not a number AND it contains a comma AND there are more than 2 characters after the comma (I'm trimming out a potential space after the comma.)
What's actually happening is, it's passing these values:
Chicago IL
Chicago, IL (with a space, even though it's trimming the space)
But failing Chicago,IL (entered initially without a space.) The reason I think it's a problem with the OR (II) is that if I remove the first part and test only for the value containing a comma, Chicago,IL passes. I thought that OR conditionals only return false if both sides of the OR are false, but that doesn't seem to be the case here.
I'm sure this is a really simple thing, but I've been staring at it for way too long and just can't see it.

That seems too complicated. If you are going to do it like that, use multiple statements (so that they can be reasoned about easier). Anyway, here is my "solution" which, admittedly, does not try to address why the original didn't work as expected:
var cityState = /^\w+(?:,\s*|\s+)\w{2}$/;
if (cityState.test(input)) {
// good
}
To accept either "City Name, State" or "City Name State", consider this (more complex) regular expression. The key to this working is the lazy modifier and the anchoring.
function isValidState (st) {
// This could be turned into an appropriate whitelist, and may include
// things like "Illinois".
return st.length == 2;
}
function parseCityState (cs) {
var match = cs.match(/^\s*(\w.*?)\s*([, ])\s*(\w+)\s*$/) || [];
var city = match[1];
var commaUsed = match[2] == ',';
var state = match[3];
if (city && state && isValidState(state)) {
return {city: city, state: state, commaUse: commaUsed}
} else {
return undefined;
}
}
Now, if you're interesting in why the original fails, consider this updated analysis for why "Chicago, IL" fails. Let x = "Chicago, IL", then:
isNaN(x) -> true
x.indexOf(' ') -> >0
x.indexOf(',') -> >0
x.split(' ') -> ["Chicago,", "IL"]
x.split(',') -> ["Chicago", " IL"]
And substituting:
true && (>0 < 0) && ["Chicago,", "IL"].pop().length > 2
||
true && (>0 > 0) && ["Chicago", " IL"].pop().trim().length > 2
Evaluation, again (note that the test for "no space" fails the first expression line because there is a space):
true && false && "IL".length > 2
||
true && true && "IL".length > 2
And evaluation again (note that both expression lines fail because "IL" only has a length of 2):
true && false && false
||
true && true && false
And ultimately this rejects the input:
false || false -> false

This is true:
I thought that OR conditionals only return false if both sides of the
OR are false
About this:
if I remove the first part and test only for the value containing a comma, Chicago,IL passes
In your fiddler example, commenting out the first test prints "fail", which implies that it is evaluating to true.
There is no problem with JS ORs. But what is what you were expecting?

I think you have a mistake on this line
x.indexOf(' ') < 0
should be
x.indexOf(' ') > 0
But if I were you, I'd use a regular expression:
var info = 'South Beach, FL';
var regex = /\w+(\w+ \w+)*\s*,\s*[a-zA-Z]{2}/;
alert(regex.test(info) ? 'Valid' : 'Invalid')

Related

Check length between two characters in a string

So I've been working on this coding challenge for about a day now and I still feel like I haven't scratched the surface even though it's suppose to be Easy. The problem asks us to take a string parameter and if there are exactly 3 characters (not including spaces) in between the letters 'a' and 'b', it should be true.
Example: Input: "maple bread"; Output: false // Because there are > 3 places
Input: "age bad"; Output: true // Exactly three places in between 'a' and 'b'
Here is what I've written, although it is unfinished and most likely in the wrong direction:
function challengeOne(str) {
let places = 0;
for (let i=0; i < str.length; i++) {
if (str[i] != 'a') {
places++
} else if (str[i] === 'b'){
}
}
console.log(places)
}
So my idea was to start counting places after the letter 'a' until it gets to 'b', then it would return the amount of places. I would then start another flow where if 'places' > 3, return false or if 'places' === 3, then return true.
However, attempting the first flow only returns the total count for places that aren't 'a'. I'm using console.log instead of return to test if it works or not.
I'm only looking for a push in the right direction and if there is a method I might be missing or if there are other examples similar to this. I feel like the solution is pretty simple yet I can't seem to grasp it.
Edit:
I took a break from this challenge just so I could look at it from fresh eyes and I was able to solve it quickly! I looked through everyone's suggestions and applied it until I found the solution. Here is the new code that worked:
function challengeOne(str) {
// code goes here
str = str.replace(/ /g, '')
let count = Math.abs(str.lastIndexOf('a')-str.lastIndexOf('b'));
if (count === 3) {
return true
} else return false
}
Thank you for all your input!
Here's a more efficient approach - simply find the indexes of the letter a and b and check whether the absolute value of subtracting the two is 4 (since indexes are 0 indexed):
function challengeOne(str) {
return Math.abs(str.indexOf("a") - str.indexOf("b")) == 4;
}
console.log(challengeOne("age bad"));
console.log(challengeOne("maple bread"));
if there are exactly 3 characters (not including spaces)
Simply remove all spaces via String#replace, then perform the check:
function challengeOne(str) {
return str = str.replace(/ /g, ''), Math.abs(str.indexOf("a") - str.indexOf("b")) == 4;
}
console.log(challengeOne("age bad"));
console.log(challengeOne("maple bread"));
References:
Math#abs
String#indexOf
Here is another approach: This one excludes spaces as in the OP, so the output reflects that. If it is to include spaces, that line could be removed.
function challengeOne(str) {
//strip spaces
str = str.replace(/\s/g, '');
//take just the in between chars
let extract = str.match(/a(.*)b/).pop();
return extract.length == 3
}
console.log(challengeOne('maple bread'));
console.log(challengeOne('age bad'));
You can go recursive:
Check if the string starts with 'a' and ends with 'b' and check the length
Continue by cutting the string either left or right (or both) until there are 3 characters in between or the string is empty.
Examples:
maple bread
aple brea
aple bre
aple br
aple b
ple
le
FALSE
age bad
age ba
age b
TRUE
const check = (x, y, z) => str => {
const exec = s => {
const xb = s.startsWith(x);
const yb = s.endsWith(y);
return ( !s ? false
: xb && yb && s.length === z + 2 ? true
: xb && yb ? exec(s.slice(1, -1))
: xb ? exec(s.slice(0, -1))
: exec(s.slice(1)));
};
return exec(str);
}
const challenge = check('a', 'b', 3);
console.log(`
challenge("maple bread"): ${challenge("maple bread")}
challenge("age bad"): ${challenge("age bad")}
challenge("aabab"): ${challenge("aabab")}
`)
I assume spaces are counted and your examples seem to indicate this, although your question says otherwise. If so, here's a push that should be helpful. You're right, there are JavaScript methods for strings, including one that should help you find the index (location) of the a and b within the given string.
Try here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#instance_methods

How do I check if a variable is null, so that I can change it later on?

A group of me and two other people are working to make a Jeopardy game (themed around United States History questions) all in JavaScript. For our final Jeopardy screen, the two teams will each bet a certain amount of money. To prevent a team from typing in random letters for a bet (i.e typing in "hasdfhgasf" instead of an actual amount), we're trying to write an 'onEvent' command that checks to see if a bet is null. If that bet is null, then the code should come up with a message on the screen that tells them to check their bets again.
We tried using statements like, if "null" or if " " but neither of these statements works. We've worked with using getNumber and getText commands, along with just regular variable comparisons with or booleans. So far, we haven't had any luck with these methods.
Here's the group of code we're having issues with:
onEvent("finalJeopardyBetSubmit", "click", function() {
team1Bet = getNumber("team1BetInput");
team2Bet = getNumber("team2BetInput");
console.log(team1Bet);
console.log(team2Bet);
if (getText("team1BetInput") == "" || getText("team2BetInput") == "") {
console.log("Check bet!");
finalJeopardyError();
} else if ((getText("team1BetInput") != 0 || getText("team2BetInput") != 0)) {
console.log("Check bet!");
finalJeopardyError();
} else if ((getNumber("team1BetInput") < 0 || getNumber("team2BetInput") < 0)) {
console.log("Check bet!");
finalJeopardyError();
} else if ((getNumber("team1BetInput") > team1Money || getNumber("team2BetInput") > team2Money)) {
console.log("Check bet!");
finalJeopardyError();
} else {
console.log("Done");
}
});
You can also check out the whole program on Code.org if you'd like to get a better look.
We expect that with the console.log commands, it should say "check bet" if the bets return as null. Instead, the code has ended up fine, and not displaying our error message, even if we type in nothing or just random letters.
a null variable will evaluate to false. Try:
if(variable){
// variable not null
}else{
// variable null
}
Convert the value to a Number first using Number(value) and then check for falsy values using the logical not ! operator. If they enter alphabetic characters, then calling Number('abc') results in NaN.
If a value can be converted to true, the value is so-called truthy. If
a value can be converted to false, the value is so-called falsy.
Examples of expressions that can be converted to false are:
null; NaN; 0; empty string ("" or '' or ``); undefined.
The ! will change any of the falsy values above to true, so you can check for all of them with just the first if statement below.
onEvent("finalJeopardyBetSubmit", "click", function() {
// Convert these values to numbers first
var team1Bet = Number(getNumber("team1BetInput"));
var team2Bet = Number(getNumber("team2BetInput"));
if (!team1Bet || !team2Bet) {
// Handle invalid number error
}
else if (team1Bet < 0 || team2Bet < 0) {
// Handle invalid range error
}
else if (team1Bet > team1Money || team2Bet > team2Money) {
// Handle insufficient funds error
}
else {
// Finish game
}
})
You can read more about the logical operators here.

When should you use parentheses inside an if statement's condition?

I have a if condition like so:
$(document).ready(function(){
var name = 'Stack';
var lastname = 'Overflow';
if( name == 'Stack' && lastname == 'Overflow' )
alert('Hi Stacker!');
});
So my alert is fired...
If I put my condition inside a brackets like this:
$(document).ready(function(){
var name = 'Stack';
var lastname = 'Overflow';
if( (name == 'Stack') && (lastname == 'Overflow') ){
alert('Hi Stacker!');
}
});
My alert is also fired...
My question is: When and why I should use parentheses inside my if condition? Thank you!
There is no much difference in your example.
You can read that for reference
Operator Precedence (JavaScript)
You use it to force associations, in your example this won't change anything. But consider this case:
A and B or C
is a lot different from
A and (B or C)
Here you would be preventing the expression from being understood as (A and B) or C which is the natural way javascript and maths do things.
Because of operator precedence :
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
you'd better read this if you want more details
But basically == (equality) weights more than && (logical-and) , so A == B is evaluated before C && D given
C <- A == B
and
D <- E == F
so adding parenthesis to C or D dont matter,in that specific situation.
Brackets can be used, if multiple conditions needs to be checked.
For ex: User is also a Stacker if full name is 'StackOverflow' then add another condition with 'Or' operator.
if(((name == 'Stack') && (lastname == 'Overflow')) || FullName =='StackOverflow')
As you can see, name and last name are placed inside one bracket meaning that it gives a result either true or false and then it does OR operation with FullName condition.
And having brackets around name, lastname and fullname fields are optional since it doesn't make any difference to the condition. But if you are checking other condition with FullName then group them into bracket.
Brackets are never required in such situations.
Of course, try to read first solution (without) and second solution (with). Second one it's clear, fast-readable and easy to mantain.
Of course if you have to change precedence (in this case you just have an AND condition, but what if you need and AND and an OR? 1 and 2 or 3 priority changes between "(1 and 2) or 3" - "1 and (2 or 3)"
Brackets () are used to group statements.
Ex - if you have an expression '2 + 3 * 5'.
There are two ways of reading this: (2+3)*5 or 2+(3*5).
To get the correct o/p based on operator precedence, you have to group the correct expression like * has higher precedence over +, so the correct one will be 2+(3*5).
first bracket requires for complex condition to ensure operator precedence correctly. lets say a example
var x=1,y=1,z=0;
if(x==0 && y==1 || z==0)
{
//always true for any value of x
}
what will happen here
(0 && 1 ||1) ----> (0 ||1)----->1
&& has high precedence over ||
if(x==0 && (y==1 || z==0)) alert('1');
{
//correct way
}
if you do not use (y==1 || z==0) bracket the condition always will be true for any value of x.
but if you use (..) the condition return correct result.
Conditional statements can be grouped together using parenthesis. And is not only limited to if statements. You can run the example below in your Chrome Developer Tools.
Example 1:
Console Execution
false && false || true
// true
flow
false && false || true
| | |
|________| |
| |
| |
false or true
| |
|_________________|
|
|
true
Example 2:
Console Execution
false && (false || true)
// false
flow
false && (false || true)
| |
|______________|
|
|
false
Helpful resources for playing around with JSInterpreter and AST's:
https://neil.fraser.name/software/JS-Interpreter/
https://esprima.org/demo/parse.html#
Consider the statement
if( i==10 || j == 11 && k == 12 || l == 13)
what you would want is if either i is 10 or j is 11 And either k is 12 or l is 13 then the result shouldbe true, but say if i is 10, j is 11, k is 10 and l is 13 the condition will fail, because the fate of equation is decided at k as aoon as && comes in picture. Now if you dont want this to happen the put it like this
if( (i==10 || j == 11) && (k == 12 || l == 13))
In this ORs will be executed first and the result will be true.

What does text != "" mean?

This is from chapter 6 in Eloquent Javascript:
Code:
function splitParagraph(text) {
var fragments = [];
while( text != "" ) // ?
if (text.charAt(0) == "*") {
fragments.push({type: "emphasized"});
etc...
I am having trouble grasping what the while loop is doing. Text is a string. Does the while loop read "while text doesn't have any characters remaining.." Is the while loop looking at every character in the string one by one making sure there is another character left?
The while loop keeps running while the condition inside is true. In this case, text != "" is true if the string in question is not an empty string.
In this particular case, I guess text must be changed somewhere inside the loop, otherwise it doesn't make sense to use a while construct here.
NOTE: Actually, in JavaScript, the != and == operators will evaluate in a pretty curious way: 0, [] and "", for instance, will all be considered equal:
"" != [] -> false
0 != [] -> false
0 != "" -> false
=== and !== can be used to enforce strict equality.
It checks if text isn't an empty string (length 0 and containing no characters).
"Is the while loop looking at every character in the string
one by one making sure there is another character left?"
Yes though the entire loop is not shown that is almost certainly what is being done.
The while condition checks if the text string is empty.
If not empty, the loop iterates through the body of the loop.
The text.charAt(0) checks the first character of the string. If a '*' character is found,
an element is added to the fragments array.
Within the body there will be code to remove the first character of the text string
and the loop then processes the next character of the string.
while( text != "" )
if (text.charAt(0) == "*") {
fragments.push({type: "emphasized"});
What does text != “” mean?
It means if the value of text can not be coerced to match ""
consider this code
if ("abc" != "") {
console.log("1 ok");
}
if ([] != "") {
console.log("2 ok");
}
if (0 != "") {
console.log("3 ok");
}
if (false != "") {
console.log("4 ok");
}
on jsfiddle
Oh dear, what happened in case 2 and 3 and 4?

Integer validation not working as expected

Thanks to some of the answers on this site, I built a function to validate an integer inside a prompt in javascript. I found out how to use isNaN and the result of % in order to meet my needs, but there must be something wrong, because is still not working: This function for validation needs to accept only integers, and as extra bonus, it will also accept a special keyword used for a different purpose later on in the program.
So, previously I had defined:
var value = prompt("Type an integer");
So after that, I made a call for the validation function, and that included three conditions: The validation warning would jump if:
1) The string is not a number
2) The string % 1 is not 0 (means is not an integer)
3) The string is not the special keyword ("extra") which is also valid as input.
The function needs to loop and keep showing the prompt until a valid data is written.
while (isNaN(value) == true && value % 1 != 0 && value != "extra") {
alert("Please, type an integer");
var value = prompt("Type an integer");
}
What am I doing wrong? Thank you so much for any ideas. I know the integer validation has been asked many times here, and here I got a few ideas, but I might be missing something...
You might be complicating things too much... A quick regular expression will do the trick.
while (!/^(\d+|extra)$/i.test(value)) {
...
}
You typed only one equal at
isNaN(value) = true
jsFiddle example
var int = 10;
var str = "10";
var isInt = function(value) {
return (str === 'extra' || !isNaN(parseInt(value, 16)) || /^\d+$/.test(value));
};
var isIntStrict = function(value) {
return (isInt(value) && typeof value !== 'string');
}
console.log('false', isInt('kirk'));
console.log('true', isInt(int));
console.log('true', isInt(str));
console.log('true', 'strict - int', isIntStrict(int));
console.log('false','strict - string', isIntStrict(str));
console.log('false','strict - string', isIntStrict('0x04'));
console.log('true','strict - string', isIntStrict(0x04));
I assume that for your purposes #elclanrs' answer is all you need here, and is the simplest and most straightforward, but just for completeness and dubious laughs, I'm pretty sure that the following would also do what you're looking for:
function isAnIntOrExtra(v) {
if (parseInt(+v) === +v && v !== '') {
return parseInt(+v);
}
else if (v === 'extra') {
return v;
}
else {
return false;
}
}
Fiddle here
These should all pass and return an integer in decimal notation:
'387' returns 387
'-4' returns -4
'0' returns 0
'2.4e3' returns 2400
'0xf4' returns 244
while these should all fail:
'4.5' returns false
'2.4e-3' returns false
'0xgc' returns false
'' returns false
'seven' returns false
And the magic-word 'extra' returns 'extra'
Of course, it'll "fail" miserably with values like '1,345', and will probably roll right over octal notation, treating it as though it were decimal notation (depending on the JavaScript engine?), but it could be tweaked to handle those situations as well, but really, you're better off with the regex.

Categories