DEV Community

Cover image for Mastering Regular Expressions
Kinanee Samson
Kinanee Samson

Posted on • Updated on

Mastering Regular Expressions

This is the second part of a series of articles, in the first article we looked at strings in JavaScript and we saw how to manipulate and work with strings, we saw how the indexOf and slice method, the length property of a string and how they make working with strings easier, if you missed that article please do check here.
In this article we will look at regular expressions.

Regular Expressions

Regular expressions are patterns that helps us to search a string against a character, they are not restricted to only JavaScript, you will find them in pHp, MySQL, C, C++ e.t.c. Regular expressions are very useful and they make working with strings as joyous as a meal in bed in the morning. You will be surprised at how conditional statements that can be replaced with a single line of regular expression. Regular expressions are also useful for data validation, you can't trust a user to enter correct data that your program requires, thus you could use regular expressions to ensure that data entered by a user will conform to a required pattern. Let's look at the syntax of regular expressions.

let myRegExp = /a/ //creates a regular expression that will search of match a in a string, or
let myRegExp = new RegExp('a') //This is also fine to work with too

Enter fullscreen mode Exit fullscreen mode

We can use use the RegExp constructor to make a regular expression or we can create one with out the constructor anyway you want is totally acceptable. The pattern you want to match or search for should be contained inside two forward slashes, and you can assign it to a variable like we did above or you call the RegExp constructor and pass two forward slashes which contains the pattern you want to match for inside double quotes. Let's see a typical use case, say we want to search for the letter a in a string, we can do this.

let myString = 'bat',
let myRegExp = /a/
console.log(myRegExp.test(myString))
//logs out true
Enter fullscreen mode Exit fullscreen mode

We get true logged out because 'bat' contains a. And The string we supplied to the test function has a match to the RegExp pattern that uses the test method. We could also test a string for more than one pattern, say we want to find a pattern that has either a, e, i, o, u, we could do this...

let searchPattern = /[aeiou]/ //the patterns we want to
//test, remember we are testing for a, e, i, o, u.
let myString = 'bet'
console.log(searchPattern.test(myString))
//logs out true
myString ='bar'
console.log(searchPattern.test(myString))
//logs out true
myString = 'but'
console.log(searchPattern.test(myString))
//logs out true
Enter fullscreen mode Exit fullscreen mode

It returns true for all value we assign to our myString variable because the search pattern says that we should test the string for any of the letters enclosed inside the square bracket. It is to note that this our pattern will always return true irrespective of the position of the pattern inside the string, however we can have more control over where the character that matches the pattern should be at, we could test if the character that we want to match should be at the starting or the end of the string. For the testing if the character is at the starting of the string, we could do this..

let searchPattern = /^a/
let myString = 'bat'
console.log(seacrhPattern.test(myString))
//logs false because a is not at the starting
//of the string
myString = 'act'
console.log(searchPattern.test(myString))
//logs true
Enter fullscreen mode Exit fullscreen mode

We use the (^) in a regular expression when we want the pattern we are searching for to appear at the beginning of the string and if the string we supplied to is not at the beginning we get false. If we want to test for the character at the end of the string we can do this.

let searchPattern = /r$/
let myString = 'Brat'
console.log(searchPattern.test(myString))
//logs out false because r is not at the end of the string
myString = 'bar'
console.log(searchPattern.test(myString))
//logs out true coz r is at the end of the string
Enter fullscreen mode Exit fullscreen mode

We can combine the two together to ensure that we are testing for a single word, like ....

let searchPattern = /^tar$/
let myString = 'Star'
console.log(searchPattern.test(myString))
//logs out false because star begins with s
myString = 'tar'
console.log(searchPattern.test(myString))
//logs out true because the string contains only the words tar
Enter fullscreen mode Exit fullscreen mode

We can also use the pipe operator to allow multiple patterns and returns true if the string matches any of the pattern just as we did in an earlier example, we use brackets and pipe operator to join multiple patterns we want in a string, example;

let searchPattern = /(^a|e|i|o|u)/
let myString = 'card'
console.log(searchPattern.test(myString))
//logs out false because we excluded a from the pattern and thus card doesnt fit 
myString = 'cool'
console.log(searchPattern.test(myString))
//logs put true because o is among the list of pattern we want to match
Enter fullscreen mode Exit fullscreen mode

We can add on extra modifiers that will allow our pattern to be more flexible, say we are searching for the pattern irrespective of the case, or we want to return more than one match or we want to perform a multi line search; by default regular expressions only search the pattern against a single string, except we tell it to go beyond that. There are three modifiers that allow us to do just that, i,g and m, let's see how we can use it in our regular expressions.

let searchPattern = /a/i //now this will match for a irrespective of the case
let myString = 'And'
console.log(searchPattern.test(myString))
//logs true because we are searching irrespective of the case.
Enter fullscreen mode Exit fullscreen mode

We can also search globally and return all matches of the string.

let searchPattern = /cat/g //this will match the pattern cat in a string for each occurence of that pattern in the string.
let pattern = new RegExp('cat', 'g') //this is how we can do this using the RegExp constructor
Enter fullscreen mode Exit fullscreen mode

If we have a multi line string and we want to search for a pattern inside it we can do this;

let searchPattern = /cat/m //this will match the pattern cat in a multi line string
let patter = new RegExp('cat', 'm') // The constructor method
Enter fullscreen mode Exit fullscreen mode

Let's dive into more practical use of RegExp, we could test a string to check if it contains only lowercase letters, or uppercase letters or only words, we could also test if a string contains special characters. Lets check a string to see if it matches a pattern of only lower case letters.

let searchPattern = /^[a-z]+$/ //this is the format for checking only lower case letters
let myString = 'Kalashin'
console.log(searchPattern.test(myString))
//logs out false becuase the string begins with an uppercase K
myString = 'kalashin'
console.log(searchPattern.test(myString))
//logs out true because we have no uppercase in the string
Enter fullscreen mode Exit fullscreen mode

You might be be wondering why we added a plus sign to the pattern, we will get to that in a short bit, if we examine the above example we are simply saying that the string must begin with a lower case and end with a lower case that's why we have the (^ and $) remember? We just add the + sign to say that we have more than one occurrence of the lowercase letter in the string. We will discuss more about that shortly. Let's match for an uppercase and a number.

let searchPattern = /[A-Z]?[0-9]+/ //we are matching against uppercase alphabets and numbers
let myString = 'kalashin'
console.log(searchPattern.test(myString)) //logs out false
myString = 'KaLAshin098'
console.log(searchPattern.test(myString))
//logs out true
Enter fullscreen mode Exit fullscreen mode

We can use quantifiers to restrict the number of characters we are trying to match against in a particular string. This is a table that contains the lot of them;

Notation Possible Number of times character appears
? 0 or 1 time
+ 1 or more time
* 0 or more times
{n} n number of times where n is an integer
{n,m} n to m number of times where n and m are integers

We are now armed with enough knowledge to make our validators, let's try and make a password validator our password validator will check for the presence of an uppercase, lowercase and number.

let isPassword = (val) => {
    if(val.length < 8){
        throw Error('Passowrd should be at least 8 characters long')
    }
    let pattern = /[a-z]?[A-Z]+[a-z]+[0-9]+/
    return pattern.test(val)
}

console.log(isPassword('Kinder092'))
//logs out true
console.log(isPassword('lanertes'))
//logs out false
Enter fullscreen mode Exit fullscreen mode

the pattern we are using to match the value specifies that a lowercase letter can occur one or more times before our uppercase letter which must appear one or more times followed by a lower case letter which must also occur one or more times which is in turn followed by one or more number, if we supply a string that doesn't match the pattern obviously we get false because it doesn't contain a lowercase, an uppercase letter and a number, you could use it for your validation. Let's build on top of that and write a validator that will check for an email.

let isEmail = (val) => {
    let pattern = /^[\w]+(\.[\w]+)*@([\w]+\.)+[a-z]{2,7}$/
    return pattern.test(val)
}

let email = 'kinanee@gmail.com'
console.log(isEmail(email))
//logs out true
email = 'playwe.careers@game.com'
console.log(isEmail(email))
//logs out true
Enter fullscreen mode Exit fullscreen mode

Let's examine our pattern, we check the string for the presence of one or more letters, next we check for the presence of a period but we have to escape it because in RegExp periods are used to represent wild card searches (any character) and then we check for the presence of one or more letters which is immediately followed by an asterisk which the @ character. The asterisk is there for emails that have more than one period before the @ symbol much like (kick.kickass.killerkicks), the @ character is immediately followed by one or more letters which is followed by a period and that period is followed by at least 2 letters. This ensures that our test can accommodate a wide range of emails, thus emails like kala.kalashin.k@yahoo.com or kim@kimk.tk

We can also use RegExp for splitting strings, we pass in a RegExp as the delimiter to the split function and it will split the strings based on that delimeter. The string methods search and match accepts RegExp as parameters, first let's see how we can split a string using a RegExp as a delimeter

let myString = 'kala, samson, John.vodka'
let splitString = myString.split([,\.])
console.log(splitString)
//logs out [ 'kala', ' samson', ' John', 'vodka' ]
Enter fullscreen mode Exit fullscreen mode

The search method returns the index of the first substring that matches the pattern that we pass to it as the search pattern, so if there are two or more words match the pattern, only the index of thefirst match from the left will be returned.

let myString = 'kala, samson, John.vodka'
console.log(myString.search(/samson/i))
//logs out 6 because the substring samson starts from the 6th position
console.log(myString.search(/kala/i))
//logs out 0 because the substring kala begins at index 0
Enter fullscreen mode Exit fullscreen mode

The match function will also accept a regular expression as a however instead of returning the index of the substring it will return an array that contains, the patter, the index of the first match, the input string we gave to it and lastly a group property.

let heroes = 'deadpool, thor, hulk, ironman, antman, spiderman'
let splitString = heroes.match(/iron/i)
console.log(splitString)
//[
// 'iron',
// index: 22,
//  input: 'deadpool, thor, hulk, ironman, antman, spiderman',
//  groups: undefined
//]

Enter fullscreen mode Exit fullscreen mode

Regular Expressions also have an exec method that will return an array that is similar to the return value of the match method. That will be all for our Regular Expression and string article for now, if there are any methods i left out, feel free to add them in the comment section, see you again soon.

Discussion (7)

Collapse
learnbyexample profile image
Sundeep

Haven't read the article yet, but just wanted to let you know about series option. In the front matter of the post, use series: <series name> (for example, series: Mastering JS). A table of content will automatically be added for all articles with the same series name.

Collapse
kalashin1 profile image
Kinanee Samson Author

Okay, thanks a lot I didn't know how to do this manually

Collapse
learnbyexample profile image
Sundeep

Glanced through the article, seems a nice introduction.

Here's some typos/suggestions I noted down:

  • new RegExp('/a/') should be new RegExp('a')
  • * and ? are switched in the quantifier table
  • [\w] can be simplified to \w
  • \w matches letters, numbers and underscores, not just letters
  • . isn't special inside character class, no need to escape
Collapse
kalashin1 profile image
Kinanee Samson Author

Okay, thanks a lot man.. I'll effect them..

Collapse
king11 profile image
Lakshya Singh

In the search function for strings don't we require forward slashes?🤔

Collapse
kalashin1 profile image
Kinanee Samson Author

There is a toward slash but correct me if I'm missing something