Regular Expressions (Regex, RegExp) in JavaScript
Hello, devs.
It's me (mario) again. Is everything OK with you all? I really hope so.
Today I will bring something very "special"! Interpretation free. 🤣
Who is ready to learn a little bit about Regular Expressions please raise both hands!
🎶 ... Cricket Sounds ... 🎶
The truth is: I didn't pass to the next phase in a job interview so I have decided to punish you, guys. 🤣 😂
No, I am just kidding. All joking aside and being very honest, I am not also a huge fan of Regular Expression because they are quite hard to understand but once you get the fundamentals, they become be very handy. My personal opinion, of course.
Please, paying close attention to this note from Wikipedia
"... Gibberish, also called _jibber-jabber_ or _gobbledygook_, is speech that is (or appears to be) nonsense. ... Example of gibberish: _ojknfauierhngiapfghniauerfhnasdfuiop_ ..."
and now compare with a random example of a regular expression:
^(?=._[!@#$%^&_"\\[\\]\\{\\}<>/\\(\\)=\\\\\\-\_+~\\:;,\\.€\\|])
What is your conclusion? For me, it seems like my cat had walked on my keyboard. ⌨️ 🐈
No, even better, looks like those old cartoons when they are cursing: 🤬
And this is exactly what you going to do after you fail trying to match a pattern in a string: 🗣️ C-U-R-S-E! 🙊
Luckily, I am here to make you cursing less, at least when it regards to regular expressions. So, let's get started (if you are still here after seeing all this weird symbols. 😉)
Requirements
- Node.js (any version is fine I guess),
- Your
will power
💪, - Optional: if you will following along, I would really recommend you using the nodemon dependency.
(nodemon is a tool that automatically restarts the node application when file changes in the directory are detected.
) so you are able to see the changes on the go.
What?
A regular expression is a string of text that allows you to create patterns that help match, locate, and manage text. source: computer hope
I know, more blah blah blah but I guarantee the phrase above will make sense very soon. Stick with me!
Settings
- Create a new
.js
file. (e.g.regexBasics.js
) - Did you have installed
nodemon
as I suggested?- (Yes) ✔️: run the following command in your terminal:
nodemon
+ your-file.js. (e.g.nodemon regexBasics.js
) - (No) ❌: run the following command in your terminal:
node
+ your-file.js. (e.g.node regexBasics.js
) ⚠️ You will need to run this command every time you make a change. Are you sure you don't want to install nodemon? You are still on time to do so. 😋
- (Yes) ✔️: run the following command in your terminal:
⚠️ I'll focus more in practical examples than the technical explanation, actually. I hope you are OK with that.⚠️
Initial Boilerplate (Explained)
/** This will be the example string where we will find the 'patterns'
I agree: It is indeed a very weird text.*/
let ourText = 'Regex in 2021 is still useful. Would your soul still be able to learn how to use regex yet in 2021? Anyway, the big dog in the bug bag is named bog.';
// This is the place where we will write your regular expressions (Please it is wrapped by "/")
let ourRegex = //**our regex will live here*//;
// In short: the hasPattern variable will store a boolean representing either a match or not.
let hasPattern = ourRegex.test(ourText);
// In short: the hasPattern variable will store the match(es)
let patternMatched = ourText.match(ourRegex);
/** ====================================
We love console.log() right? XD
========================================*/
// They are here so we are able to see the results in our console.
console.group('The Result of our comparison');
console.log('Has Pattern?:', hasPattern);
console.log('The Pattern: ', patternMatched);
console.groupEnd();
Are you ready ?
After have written the boilerplate, let's (finally) started our journey. The only thing we will change is the value of the ourRegex
variable.
Matching Literal Strings
Please type the following, save the file and look at your console.
let ourRegex = /Regex/;
It should print something like this:
The Result of our comparison
Has Pattern?: true
The Pattern: [
'Regex',
index: 0,
input: 'Regex in 2021 is still useful. Would your soul still be able to learn how to use regex yet in 2021? Anyway, the big dog in the bug bag is named bog.',
groups: undefined
]
Shallow Explaining:
-
Has Pattern?: true
becauseourText
contains the pattern fromourRegex
. -
The Pattern: [
-
Regex
is the value ofourRegex
-
index: 0
indicates where in the string it was found. (ourText
starts with the wordRegex
so its index is 0) -
input:
is theourText
content. -
groups: undefined
I am going to explain it later on. 😋
-
The pipe operator |
Think the pipe as the famous OR
conditional operator. In JavaScript it is known as ||
. (double pipe)
What would you expect if we change ourRegex
with this new content? 🤔
let ourRegex = /bubble|Regex/;
Did you guess it right?
It is exactly the same result from our Matching Literal Strings
session.
Here is why: It returns the first value matched.
For example:
let ourRegex = /bubble|Regex/;
- returns "Regex" because the pattern "Regex" is there in
ourText
.
let ourRegex = /Regex|bubble/;
- also returns "Regex" for the same reason above.
let ourRegex = /naruto|bubble/;
- returns the values
false
to "Has Pattern?" andnull
for "The Pattern".
Flags 🏁
It is very important noticing the flags are placed outside of the slashes \
- The
i
flag stands for "ignore case".
let ourRegex = /STILL/i;
It returns Has Pattern?: true
because after ignoring case the pattern still
is still there. 🥁
- The
g
flag stands for "globally". In other words, it is going to search and return all the matches ofourRegex
pattern.
let ourRegex = /still/g;
The result in our console will be:
The Result of our comparison
Has Pattern?: true
The Pattern: [ 'still', 'still' ]
Cool, isn't it? 😎 Now try to combine both flags and let me know your results. :)
📌 Feel free to use this example.
let ourRegex = /regex/gi;
The dot operator .
Also called as "wildcard" stands for one UNSPECIFIED character. I have highlighted the "unspecified" word because I know when we reach the +
operator you will come back here. I admit I have done it several times before and I still do it. 😅
🚨 Worth noticing we combined it with the g
flag, otherwise the value returned would be either null
or the first occurency of the pattern.
let ourRegex = /.l/g;
So, in human language (Are we humans?) we are pretty much saying something like:
" - Hey regex, you pretty little thing I don't care what comes before the letter l
but bring me it along with the letter."
The result has been explained below.
The Pattern:
[
'il', // Pattern found on the first "still" word
'ul', // Pattern found on the "Would" word
'ul', // Pattern found on the "useful" word
'ul', // Pattern found on the "soul" word
'il', // Pattern found on the second "still" word
'bl', // Pattern found on the "able" word
' l' // Pattern found on the "learn" word (Note there is one " " before " learn")
]
The brackets operator []
It is useful for matching multiple possibilities. The only thing we need to do is wrap them (the possibilities) using [ ]
.
Let's say we want to get all the words which, between the consonants "b" and "g", have the "a", "i" or "u" vowels.
Tldr We want to match the bag, big and bug words but not bog.
🚨 Please, remember to use the g
flag, otherwise the result will always be the first match found, in our case, the word big. 🚨
let ourRegex = /b[aiu]g/g;
The result in the console should be something like:
The Result of our comparison
Has Pattern?: true
The Pattern: [ 'big', 'bug', 'bag' ]
[OFF-TOPIC] - Hydration Break 💡🚰
We are doing good, right? Yes we are!
You can skip this part if you want to but only after you hydrate yourself, deal?. (☕ 🥛 🥤)
I just would like to share with you guys what motivates me to write this article. I promise to be concise and don't take too much of your time. 🤞
This crazy moment we are now living globally brought me, along with all the harm which is not worth mentioning here, some free time I didn't have before that is, at least, something good.
I have got time to read my favorite books, became more active writing articles, been learning how to play ice hockey (my home country has ice only inside of our fridges 😹) and last but not least, I could conclude some courses I have started some time ago, for example the CS50, FCC JavaScript Intermediate Algorithms to mention some.
What is my point here?
Regular expressions had an important role in the last two items of my list above. If it was not for knowing the basics of regex, I would probably complete some tasks there using a combination of hundreds .split()
, .splice()
, .slice()
, indexOf()
, toLowerCase()
, toUpperCase()
, for loops
, if-else
and so on. 🤯
That is to say, in addition to making the code more difficult to read and maintain, it would include unnecessary lines of code to perform "simple" tasks.
Maybe learning regex will help you somewhere somehow. And if it is the case my mission here is accomplished!
Still don´t believe me? You are so obstinately unmoving (a.k.a. stubborn 😅 🤣 😂)
OK, I guess we have had enough hydration time. A few more examples and we are done for the part 1.
The Range Operator -
We can also search for patterns given a determined range, for example, if we want to find any of these following words below:
bag, bbg, bcg, bdg, beg, bfg, bgg, bhg and big
.
Sorry, I couldn't think in a better example without changing the ourText
value.
(I have already changed it several times before in order to fit it in our needs. 🤦)
let ourRegex = /b[a-i]g/g;
The result on console:
The Result of our comparison
Has Pattern?: true
The Pattern: [ 'big', 'bag' ]
Basically, when we use the -
operator between the a
and i
letters is the same as doing /b[abcdefghi]g/g
but in a more attractive way. 💋
This approach works with numbers as well. I am sure you can guess what /200[3-7]/g
would bring back to us if we have a string such as 2000 2001 2003 2004 2005 2006 2007 2008 2009
;
Exactly!! 🤓
The Result of our comparison
Has Pattern?: true
The Pattern: [ '2003', '2004', '2005', '2006', '2007' ]
Quick Notes: 🗒️✏️
- You can combine them:
/[a-zA-Z0-9]/
- Case matters:
a-z
stands for lowercase characters andA-Z
for the uppercase ones. - You can combine even more:
- (
Imagine the case you don't care about the case) 🤨 💫 - If the letter case doesn't matter and you want to match patterns globally you could write something like:
/c[a-z]t/gi
or/c[A-Z]t/gi
since thei
flag ignores the letter's case.
- (
The Negation Operator ^
(Disambiguation)
The ^
operator has two totally different usages. For now, just focus on this example. Once you have grasped the first, the other one will be easy peasy lemon squeezy. 🍋
I have decided to don't include bog
in your list. Why? Because this post will spread around the world and I don't feel comfortable with my imaginary dog 🐶 being noticed by other people. I am really jealous about it.
No idea of what I am talking about? Read the ourText
content again. 🔖
Simple, the only thing we needed to do is negate the o
letter. How?
let ourRegex = /b[^o]g/g;
Voilà, we have got a brand new result logged in our console: ✔️ 👍
The Result of our comparison
Has Pattern?: true
The Pattern: [ 'big', 'bug', 'bag' ]
And that is pretty much it for the part 1, guys. 🎉 🥳
I will probably release the part 2 either on Saturday evening or on Sunday afternoon but before doing that I would like to ask for something.
And no, I won't ask for money or similar. 😂 💸 So here I go. (Wario´s voice from Mario Kart 64)
- Is everything understandable so far?
- Should I change the content of
ourText
string for a new one? - Would you like to have a quick challenge at the end of this series? I was thinking about to provide you a phrase and ask you guys to try to find a pattern on it so we could solve it together and share our different solutions. Also if for any reason you don't want to post your approach in the comments, you could send me it privately and I would be glad to review it and/or help you. 🤝
Don't be shy! Let's make mistakes together. 💪
"Anyone who has never made a mistake has never tried anything new." (Albert Einstein)
Have a nice weekend, everyone!
[EDITED]: The part 2 is already on fire! 🔥 🕶️
The part 3 is also out there.😋
🎶 "... Cheerio, cheerio, toodle pip, toodle pip ..." 🎶
Top comments (2)
That first, "random" example you gave is a poor one because it's written badly. You wouldn't need to escape most of those characters when they're in a character class, and the whole thing would look less like a zebra!
Hi, Ben. Thanks for your comment. :)
It is indeed a very poor example but I really meant random. I had just googled "regex", "stackoverflow" and "javascript" and that was the first result that showed up.
I have connections neither with the person who created the question nor with the people who answered it. 😉 For that reason I have included the source.
From now on I'll always see that example in particular as a zebra. 🦓
Thanks for that. 🤣