Monday, November 6, 2017

Workin' My Way Back to RegEx...

Ok, so in the past week, my coding activities have included the following:

  1. Working on "Intro to JS" materials to help co-teach the Front End Web Development course my JavaScript mentor Tom teaches at Betamore Academy;
  2. As a direct outcome of item 1, realizing that even 15 months in to learning JS, there are serious potholes in the roadway of my self-taught JS journey;
  3. Working through pothole-filling material in my favorite JS book, "JavaScript and jQuery: Interactive Front-End Development," by Jon Duckett;
  4. Getting my ass kicked -- repeatedly -- on a level 7 Codewars Kata (see item 2 about holes, above).

Today, let's talk about the kata.  It is the "compare strings by sum of chars" challenge, wherein you are given two strings and asked to determine whether or not they are equal by dint of their ASCII values. If the arg strings are null, empty or contain anything other than a letter (i.e., numbers or punctuation or, say, the turd emoji) the string's value is zero.

I decided to approach the challenge in pure JS, no regex. I then wrote out the code logic in plain words. I will skip boring you with this because it is in the final code, in the form of comments.

Where I got stuck: 
  • First, on null string test cases. Because, for what I now realize was an embarrassingly long time, my code proceeded upon the assumption that null had length of zero -- when of course you can't determine length of something that does not exist. It finally occurred to me to look at MDN  to see why my code kept returning an error -- that told me, in plain English, "TypeError: Cannot read property 'length' of null". I was extremely sure that I was right and JS simply wrong. Sigh. This is actually weird for me, because I typically assume the opposite -- last week I had some freaky browser thing going on where console.log(whatever) was not displaying, and I was sure it was me. As in, I had somehow messed up in applying one of the most fundamental JS tools in the box.  Turns out there is a toggle in console that I had accidentally flipped, turning off display of anything NOT an error. Gosh, thanks, Chrome!
  • Next, I was also SUPER sure of another thing that also turned to be ahem wrong wrong wrong. My test case for whether string elements were alpha only characters involved converting .toUpperCase() -- the instructions specified treating all letters as capitals even if passed as lower case -- and then checking if the ASCII value was greater than or equal to 65 (the value of capital "A") and less than or equal to 90 (the value of cap "Z").  Unfortunately, I was confident that you could do this:
                  if(65 <= str1Val <=90){do some stuff}


         When it turns out, no you can't.  it's got to be:

                         if(str1Val>=65 && str1Val<=90){do that stuff}

    Dude, I was just trying to make my code a little sleeker. Though I guess i               could drop two equal signs and achieve the same thing with 

                         if(str1Val>64 && str1Val<91){do that stuff}

My thought with using 65 and 90 with the greater/lesser equals operators was to make my code more readable -- i.e., make it plain that these numbers represented A and Z. Like, more readable  for all the ASCII savants who will ever stumble across my Codewars solution and instantly convert this in their heads and be impressed.

 function compare(s1, s2) {  
 //establish counter variables to hold the ASCII code values of the strings  
 let s1Sum=0;  
 let s2Sum=0;  
 //if s1 is null OR empty (has a length of zero) return s1Sum=0:  
 if(s1 == null || s1.length==0) {  
  s1Sum=0;  
 } else {  
 //else, convert s1 to upper case and loop over each character in the string,   
 //assigning the ASCII value (obtained with `charCodeAt()` for each position)  
 //to a newly inititalized variablie, s1Val:  
 s1=s1.toUpperCase();  
 for(var i=0; i<s1.length; i++){  
  let s1Val = s1.charCodeAt(i);  
  //IF the value is between 65 and 90 (the capital alphabet ASCII values),  
  //add s1Val to s1Sum:  
   if(s1Val>=65 && s1Val <= 90){  
    s1Sum += s1Val;  
   }   
  //if it's not between 65 and 90, then it is a number or other symbol, so return   
  //s1Sum = 0:  
   else {  
    s1Sum=0;  
    }  
   }  
  }  
  //Now repeat same logic for the second passed arg, s2:  
  if(s2==null || s2.length==0) {  
  s2Sum = 0;  
  }else {  
   s2=s2.toUpperCase();  
   for(var i=0; i<s2.length; i++) {  
   var s2Val = s2.charCodeAt(i);  
   if(s2Val>=65 && s2Val <= 90){  
   s2Sum += s2Val;  
   } else {  
    s2Sum=0;  
    }  
   }  
  }  
  //Finally, compare the two counter variables, s1Sum and s2Sum, returning   
  //true if equal and false if not equal  
 if(s1Sum === s2Sum) {  
   return true;  
  } else {  
   return false;  
  }  
 }

So!  That got things working. Notice, however, that a few lets aside, I am still thinking in ES5. Tomorrow's challenge: refactor into more modern JS, if that is possible. And then a side quest: repeat the challenge, this time using regex.

No comments:

Post a Comment