Categories
JavaScript What I Learned Today

JavaScript: lookaround assertions

Today I learned about javascript lookahead, lookbehind , and both negative lookahead and lookbehind assertions. The freecodecamp curriculum briefly touched on it but not enough for me to fully grasp the idea of it. It took me about 8 hours ( split between two days ) to understand how to use’em.

 I’ll get to what they are in a minute, but first I’d like to stay that the way they’re described is a bit confusing. The lookahead / lookbehind way of teaching just didn’t sit well with me. For me to grasp the concept behind them, I needed to think of them as little if statements ( or mini ternary operators ).

Keep that in mind for now; as you’ll see what I’m talking about.

Javascript assertions ( lookahead, lookbehind, etc) were added to ES6, and provide you with additional superpowers. They give you the ability to match given criteria if and only if  set character(s) is present before or after the criteria that you’re trying to match, hope you understood that because that’s the probably the best that I can do at this time. If I come up with a better way of breaking it down, I’ll update this post.

Before I give you some examples, here are the assertions that you will need to be familiar with:

x(?=y)

Lookahead assertion:  This assertion only matches ‘x’ if and only if ‘y’ is followed by ‘x’.

x(?!y)

Negative lookahead assertion: This only matches if ‘x’ is NOT followed by ‘y’.

(?<=y)x

Lookbehind assertion: This assertion only matches ‘x’ if and only if y’ is directly before  ‘x’’.

(?<=y)x

Negative Lookbehind assertion: This assertion only matches ‘x’ if and only if ‘y’ is not directly before  ‘x’.

If you would like to learn more about them, check out MDN here:  Mozilla’s Javascript MDN

Lets start with some lookbehind assertion examples.

(?<=y)x 

let phoneNumbers = `
            (718)535-6873
            (413)535-6873
            (803)535-7848
            (718)535-9873
            (212)555-6854
            (718)457-6113`;

let myRegex = /(?<=\(718\))\d{3}-\d{4}/g

//output [ '535-6873', '535-9873', '457-6113' ]

In the example, above,  \d{3}-\d{4}  is our ‘x‘ and  (? <=\718\)) is our ‘y’. It matches because the seven digits immediately follow the parentheses, not the number 8. So if this regular expression could speak, what would it actually say?

 “I will provide you with 7 digits for a phone number if and only if there is an area  code of 718 surrounded by parenthesis  preceding the 7 digits.”

What happens when I remove the right parentheses?

let myRegex2 = /(?<=\(718)\d{3}-\d{4}/ //output null
                        /                        
                     I removed 
                  the right parentheses.
            Meaning, it is essentially looking for:
                    (718535-6873

We’re gifted a result of null.Why? Because based on the  string, a parentheses comes before the ‘535’, not an‘8’.

Here is another example using a  lookbehind assertion. 

let myFruits= `oranges banana pears banana peach banana`;
let myRegex3 = /(?<=pears )banana/

//output [ 'banana', index: 21, input: 'oranges banana pears banana peach banana', 
  groups: undefined ] 

So what is this one saying?

 “I will provide you with the word ‘banana‘, if an only  and  only if the word ‘pears‘ followed by a space is preceding the word ‘banana’ “

NOTE: Within the lookbehind, notice the space between the word pears and the closing parentheses.

 let myRegex3 = /(?<=pears )banana/
                         /
              This is your white space.
                 or you can use  /(?<=pears\s)banana/

Lookahead example

//* Providing website names with a TLD of.com

let myHtmlCode = `
         href=\'www.SITE1.com\'>yourSite
         href=\'www.SITE2.org\'>yourSite
         href=\'www.SITE3.net\'>yourSite
         href=\'www.SITE4.com\'>yourSite
         href=\'www.SITE5.io\'>yourSite
`;

let myRegex4 = /\w+\d(?=\.com)/g

//output [ 'SITE1', 'SITE4' ] ​​​​

Negative lookahead example

//change the id's to classes for both green and red buttons while excluding the orange id

let myHtml = `
          class='blueBtn'
          id='greenBtn'
          id='redBtn'
          id='orange'
`;

let myRegex5 = /id(?!\W+orange)/g
let changeToClass = myHtml.replace(myRegex5, 'class')

//output, below

      class='blueBtn'
      class='greenBtn'// <--- changed from id to class
      class='redBtn' // <--- changed from id to class
      id='orange' //<--- Untouched!

I think this is a pretty cool tool to have in your utility belt. If you found this post useful, let me know in the comments below.