"A regular expression is a sequence of characters that forms a search pattern. The search pattern can be used for text search and text replace operations. A regular expression can be a single character, or a more complicated pattern." -w3schools
Regular expression (regex) methods can be a powerful tool for developers, but they can also be daunting to understand and use. In this technical blog post, we will simplify the topic of regex methods used in JavaScript (JS) by collating all the necessary information in one place. We will cover the basics of regular expression methods, including syntax, and some common use cases. This blog post is organized for quick reference about the methods usable with regex and sometimes utilizes regex syntax like flags, character classes, assertions, and quantifiers to showcase the different ways the methods could be used. By the end of this post, you will have a comprehensive understanding of regular expression methods and be better equipped to use them in your own development projects.
-Methods-
Regular expressions are used with the RegExp Object methods
test()
andexec()
and the String Object methodsmatch()
,matchAll()
,replace()
,replaceAll()
,search()
, andsplit()
. -MDN Web Docs
-Regular Expression Object Methods-
The two methods we use on the regex object are test()
and exec()
. Regex methods are called on our RegExp Object and the parameter is the string we would like to search through: regex.method(string)
-test() Method-
The test()
method returns a Boolean value: true
if the pattern is found or false
if the pattern is not found.
const regex = /pattern/;
const string1 = "This sentence contains the pattern";
const string2 = "This sentence does not contain it";
//When the pattern will be found
console.log(regex.test(string1)); //Expect: true
//When the pattern will not be found
console.log(regex.test(string2)); //Expect: false
-Common Use Case for test() Method-
Two common use cases for the test() method are when you want to ensure that a user inputs a valid phone number(i.e. correct amount of digits) or a valid email address (i.e. contains an '@' or a '.com'). Let's examine checking the validity of a US phone number. The code to test for a valid United States phone number could look like this:
const validUSNumberRegex =
/^(\+?1[-. ]?)?\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}$/;
//If the number is valid
let userInputNumber = +1 333-333-4444;
console.log(validNumberRegex.test(userInputNumber));
//Expect: true
//If the number is NOT a valid US Number
let userInputNumber = +974 4444 4444;
console.log(validUSNumberRegex.test(userInputNumber));
//Expect: false
With a true
return, we could continue with the provided information as planned. With a false
return, we could instruct the user to please provide a correct US number:
if(validUSNumberRegex.test(userInputNumber) == true){
//Save number for later use
validPhoneNumbersArray.push(userInputNumber);
} else {
//Request User to resubmit a correct US number
alert("Please enter a valid US phone number.")
}
-exec() Method-
The exec()
method returns an array of information if the pattern is found: ['pattern', index: 'index found at', input: 'the string the pattern was found', groups: 'if the pattern belongs in a group']
. The exec()
method returns null
if the pattern is not found. The exec()
method is useful when you need to find the next match of a pattern within a string and you want to work with the individual match and its capturing groups before moving on to the next match. This method stores the index of the previous match, so when called again, will return the next match in the string.
const regex = /pattern/;
const string1 = "This sentence contains the pattern";
const string2 = "This sentence does not contain it";
// When the pattern will be found
console.log(regex.exec(string1));
/* Expect: [
'pattern',
index: 27,
input: 'This sentence contains the pattern',
groups: undefined]
*/
// When the pattern will NOT be found
console.log(regex.exec(string2)); //Expect: null
-Common Use Case for exec() Method-
Let's say we have been tasked to compile all the email addresses that were submitted from a multitude of users. For example, hundreds of thousands of users have submitted messages that look something like:
Hello, software developer. My name is John Wick. My email address is JohnWick@Unbeatable.com, my wife's email is JohnWicksWife@beatable.com, and my dog's email is JohnWicksDog@theRealLoveInterest.com. I am interested in joining your company because....
While you could read every single message and manually input the names and emails and any other pertinent information, it would be exponentially faster to use the exec()
method. Using capture groups in your regex would further allow you to breakdown the information you are retrieving. Here is a while loop that will grab all the emails, then further dissect the email using the 'groups' property from the exec()
method (let's assume the quote above has already been saved to the variable userLetters
):
const emailRegex =
/(?<user>\w+[!#$%&'*+\-/=?^_`{|]{0,1}\w+)@(?<domain>[a-zA-Z]+[-.]?[a-zA-Z0-9]+)\.(?<top>[a-zA-Z]{2,3})/g;
let submittedEmails = [];
let match;
while((match = emailRegex.exec(userLetters)) !== null) {
submittedEmails.push({
'userEmail': match[0],
'userName': match.groups.user,
'domainName': match.groups.domain,
'topDomain': match.groups.top
})
}
console.log(submittedEmails);
/* Expect: [
{
userEmail: 'JohnWick@Unbeatable.com',
userName: 'JohnWick',
domainName: 'Unbeatable',
topDomain: 'com'
},
{
userEmail: 'JohnWicksWife@beatable.com',
userName: 'JohnWicksWife',
domainName: 'beatable',
topDomain: 'com'
},
{
userEmail: 'JohnWicksDog@theRealLoveInterest.com',
userName: 'JohnWicksDog',
domainName: 'theRealLoveInterest',
topDomain: 'com'
}
]
*/
Not only are we now able to email all users who submitted valid emails, we could filter it to only email users utilizing the 'Unbeatable' domain name!
-String Object Methods-
These methods are match()
, matchAll()
, replace()
, replaceAll()
, search()
, and split()
.
As mentioned earlier, we can use regex with methods used on String Objects: string.method(regex)
-match() Method-
The match()
method in conjunction with the global flag will return an array of strings if matches are found: ['match1', match2, match3]
or null
if no matches are found. If the global flag is not used, the method will return the first match in the same format as the exec()
method.
-Common Use Case for the match() Method-
Let's again say we have been tasked to compile certain information, but this time we need to only grab birthdates from the data. We don't have need to also grab additional information like how the exec()
method provides, just an array of the birthdates. The user submitted info could look like this:
Hello again, Software Developer. My name is John Wick. I realized in my last message I forgot to include our birthdates. My birthday is 09/02/1964. My wife's birthday is 11/16/1966. My dog was born on 03/22/2020.
Let's assume we have already stored information above to a variable userInfo
. Our code to grab the birthdays using the match()
method could look like this:
const birthdayRegex = /\d{2}\/\d{2}\/\d{4}/g;
const birthdays = userInfo.match(birthdayRegex);
console.log(birthdays);
//Expect: [ '09/02/1964', '11/16/1966', '03/22/2020' ]
The above code regex only returns matches in the format 'xx/xx/xxxx'. You would need to alter the regex to match other formats. Once we have the data, we could use it to determine age demographics, how many adults, how many minors, etc...
-matchAll() Method-
The matchAll()
method is similar to the exec()
method in that it returns an array of information about the match.
The matchAll() method returns an iterator of all results matching a string against a regular expression, including capturing groups. MDM Web Docs
Simply put, the matchAll()
method does what exec()
method can do when working with all matches at once, but the matchAll()
method can do it a bit more concisely, making it easier to read.
-Common Use Case for the matchAll() Method-
To showcase how the matchAll()
method is more concise than the exec()
method, we will use the same scenario as before. Compare the two codes and see the differences. Again we have this user info:
Hello, software developer. My name is John Wick. My email address is JohnWick@Unbeatable.com, my wife's email is JohnWicksWife@beatable.com, and my dog's email is JohnWicksDog@theRealLoveInterest.com. I am interested in joining your company because....
Assume again the above quote has been saved to the variable userLetters
. Using the matchAll()
method, the code might look like this:
const emailRegex =
/(?<user>\w+[!#$%&'*+\-/=?^_`{|]{0,1}\w+)@(?<domain>[a-zA-Z]+[-.]?[a-zA-Z0-9]+)\.(?<top>[a-zA-Z]{2,3})/g;
const matches = [...userLetters.matchAll(emailRegex)].map(match => ({
user: match.groups.user,
domain: match.groups.domain,
top: match.groups.top
}));
console.log(matches);
/* Expect:
[
{ user: 'JohnWick', domain: 'Unbeatable', top: 'com' },
{ user: 'JohnWicksWife', domain: 'beatable', top: 'com' },
{ user: 'JohnWicksDog', domain: 'theRealLoveInterest', top: 'com' }
] */
-replace() Method-
The replace()
method is used to replace a specified value or pattern in a string with a new value or string. The method returns a new string with the replaced value or pattern. It can be used with a regular expression or a string value to replace all occurrences (if the 'g' flag is used) of the specified value or pattern, or a specified number of occurrences. The replace()
method does not modify the original string but returns a new string with the replaced values. The method takes two parameters: (regex, replacement) string.replace(regex, replacement)
. The replacement can be a string value, or a function. The function's result (return value) will be used as the replacement string. MDM Web Docs
const originalStr = "Regular Expressions are FUN, FUN, FUN!";
const regex = /fun/i;
const newWord = "AMAZING";
const newStr = originalStr.replace(regex, newWord);
console.log(originalStr);
//Expect: "Regular Expressions are FUN, FUN, FUN!"
console.log(newStr);
//Expect: "Regular Expressions are AMAZING, FUN, FUN!"
What if we wanted to replace the first two 'FUN' with 'AMAZING'? With the help of a count variable, the code could look like:
const originalStr = "Regular Expressions are FUN, FUN, FUN!";
const regex = /fun/ig;
const newWord = "AMAZING";
let count = 0;
const newStr = originalStr.replace(regex, (match) => {
count++;
return count < 3 ? newWord : match;
});
console.log(newStr);
//Expect: "Regular Expressions are AMAZING, AMAZING, FUN!"
-Common Use Case for the replace() Method-
I actually just recently used the replace()
method in a Recipe App I created. My app fetches information from an API, then dynamically renders the content to the user. I had an issue with some of the results from the API containing single quotes in the label property, which caused errors when working with the localStorage. If a user searched only for "Central Europe" in the cuisine dropdown box, the first recipe displayed used to be "Brined Ramps from 'Bar Tartine'". I fixed this within the Recipe Class using the replace()
method. The code is essentially this:
//Original label: Brined Ramps from 'Bar Tartine'
this._label = recipe.recipe.label.replace(/'/g, '');
//New label: Brined Ramps from Bar Tartine
-replaceAll() Method-
The replaceAll()
method does exactly as you'd expect, replaces all occurrences of a given substring in a string. Unlike replace()
, which only replaces the first occurrence of the pattern unless the global flag is set, replaceAll()
replaces all occurrences by default. The replaceAll()
method, like replace()
, takes two arguments: the pattern to be replaced and the replacement string. The pattern can be either a string or a regular expression, and the replacement string can be either a string or a function that returns a string. One important thing to note is that replaceAll requires a global regular expression pattern, meaning that the g flag must be specified in the regular expression pattern. If the g flag is not specified, a TypeError will be thrown.
This replaceAll()
does NOT need a global flag:
const originalStr = "Regular Expressions are FUN, FUN, FUN!";
const newStr = originalStr.replaceAll("FUN", "AMAZING");
console.log(newStr);
//Expect: "Regular Expressions are AMAZING, AMAZING, AMAZING!";
This replaceAll()
DOES need a global flag:
const originalStr = "Regular Expressions are FUN, FUN, FUN!";
const newStr = originalStr.replaceAll(/FUN/g, "AMAZING");
console.log(newStr);
//Expect: "Regular Expressions are AMAZING, AMAZING, AMAZING!";
-Common Use Case for the replaceAll() Method-
Exactly the same as replace()
, when you need to replace ALL substrings.
-search() Method-
The search()
method returns the index of the first match. If no match is found, it returns -1. The syntax for search()
is: string.search(regex)
.
When you want to know whether a pattern is found, and also know its index within a string, use
search()
-MDM Web Docs
const string = "Regular Expressions are FUN, FUN, FUN!";
const indexOfRegex = string.search(/[A-Z]{2,}/);
console.log(indexOfRegex);
//Expect: 24
Now you might be thinking: "When would I need to know the index of a substring?" Great question! Knowing the index of a particular substring in a larger string can be useful in a variety of ways. For example, if you want to extract a specific piece of information from a string, you can use the indexOf
method to find the starting index of that information and then use string manipulation techniques to extract it. Additionally, you can use the index to replace or modify specific parts of a string. The index can also be useful for performing more advanced operations such as parsing or tokenizing a string.
-split() Method-
The split()
method splits a string into an array of substrings based on the regex. split()
does not change the original string. This method can take two parameters: string.split(regex, limit)
.
The second parameter, 'limit', is optional. When used, the method will continue splitting the string until it has split limit
number of times.
//No limit set
const stringToSplit = "Regular Expressions are FUN, FUN, FUN!";
let arrayOfSplitStr = stringToSplit.split(/\s/);
console.log(arrayOfSplitStr);
/* Expect:
[ 'Regular', 'Expressions', 'are', 'FUN,', 'FUN,', 'FUN!' ]
*/
//Limit set
let arrayOfSplitStr = stringToSplit.split(/\s/, 4);
console.log(arrayOfSplitStr);
// Expect: [ 'Regular', 'Expressions', 'are', 'FUN,' ]
-Common Use Case for the split() Method-
We are now tasked with listing all the sentences in a 10,000 word document. No idea why we're tasked to do this, but it doesn't matter. We can write a simple regex to handle the different ways a sentence can end and use it in a split()
.
const multiSentenceDoc = "I LOVE CODING! Isn't problem solving great? I'm excited being a software developer.";
const splitRegex = /(?<=[.?!])\s+(?=[A-Z])/;
const splitArray = multiSentenceDoc.split(splitRegex);
console.log(splitArray);
/* Expect: [
'I LOVE CODING!',
"Isn't problem solving great?",
"I'm excited being a software developer."
]
-Conclusion-
In conclusion, regular expressions are a powerful tool in any developer's toolkit, and the various string methods built upon them can provide significant benefits in terms of string manipulation and data processing. By mastering these methods, developers can improve their efficiency and productivity, and unlock new possibilities for their applications. Whether you're a beginner or an experienced developer, taking the time to learn and understand regular expressions and their associated methods can open up a world of possibilities and help you take your coding skills to the next level.
Top comments (0)