In this article we’ll cover various methods that work with regexps in-depth.
str.match(regexp) finds matches for
regexp in the string
It has 3 modes:
regexpdoesn’t have flag
g, then it returns the first match as an array with capturing groups and properties
index(position of the match),
input(input string, equals
g, then it returns an array of all matches as strings, without capturing groups and other details.
If there are no matches, no matter if there’s flag
That’s an important nuance. If there are no matches, we don’t get an empty array, but
null. It’s easy to make a mistake forgetting about it, e.g.:
If we want the result to be an array, we can write like this:
let result = str.match(regexp) || ;
str.matchAll(regexp) is a “newer, improved” variant of
It’s used mainly to search for all matches with all groups.
There are 3 differences from
- It returns an iterable object with matches instead of an array. We can make a regular array from it using
- Every match is returned as an array with capturing groups (the same format as
- If there are no results, it returns an empty iterable object instead of
let str = '<h1>Hello, world!</h1>'; let regexp = /<(.*?)>/g; let matchAll = str.matchAll(regexp); alert(matchAll); // [object RegExp String Iterator], not array, but an iterable matchAll = Array.from(matchAll); // array now let firstMatch = matchAll; alert( firstMatch ); // <h1> alert( firstMatch ); // h1 alert( firstMatch.index ); // 0 alert( firstMatch.input ); // <h1>Hello, world!</h1>
If we use
for..of to loop over
matchAll matches, then we don’t need
Array.from any more.
Splits the string using the regexp (or a substring) as a delimiter.
We can use
split with strings, like this:
But we can split by a regular expression, the same way:
str.search(regexp) returns the position of the first match or
-1 if none found:
The important limitation:
search only finds the first match.
If we need positions of further matches, we should use other means, such as finding them all with
This is a generic method for searching and replacing, one of most useful ones. The swiss army knife for searching and replacing.
We can use it without regexps, to search and replace a substring:
There’s a pitfall though.
When the first argument of
replace is a string, it only replaces the first match.
You can see that in the example above: only the first
"-" is replaced by
To find all hyphens, we need to use not the string
"-", but a regexp
/-/g, with the obligatory
The second argument is a replacement string. We can use special characters in it:
|Symbols||Action in the replacement string|
||inserts the whole match|
||inserts a part of the string before the match|
||inserts a part of the string after the match|
||inserts the contents of the parentheses with the given
For situations that require “smart” replacements, the second argument can be a function.
It will be called for each match, and the returned value will be inserted as a replacement.
The function is called with arguments
func(match, p1, p2, ..., pn, offset, input, groups):
match– the match,
p1, p2, ..., pn– contents of capturing groups (if there are any),
offset– position of the match,
input– the source string,
groups– an object with named groups.
If there are no parentheses in the regexp, then there are only 3 arguments:
func(str, offset, input).
For example, let’s uppercase all matches:
Replace each match by its position in the string:
In the example below there are two parentheses, so the replacement function is called with 5 arguments: the first is the full match, then 2 parentheses, and after it (not used in the example) the match position and the source string:
If there are many groups, it’s convenient to use rest parameters to access them:
Or, if we’re using named groups, then
groups object with them is always the last, so we can obtain it like this:
Using a function gives us the ultimate replacement power, because it gets all the information about the match, has access to outer variables and can do everything.
This method is essentially the same as
str.replace, with two major differences:
- If the first argument is a string, it replaces all occurrences of the string, while
replacereplaces only the first occurrence.
- If the first argument is a regular expression without the
gflag, there’ll be an error. With
gflag, it works the same as
The main use case for
replaceAll is replacing all occurrences of a string.
regexp.exec(str) method returns a match for
regexp in the string
str. Unlike previous methods, it’s called on a regexp, not on a string.
It behaves differently depending on whether the regexp has flag
If there’s no
regexp.exec(str) returns the first match exactly as
str.match(regexp). This behavior doesn’t bring anything new.
But if there’s flag
- A call to
regexp.exec(str)returns the first match and saves the position immediately after it in the property
- The next such call starts the search from position
regexp.lastIndex, returns the next match and saves the position after it in
- …And so on.
- If there are no matches,
So, repeated calls return all matches one after another, using property
regexp.lastIndex to keep track of the current search position.
In the past, before the method
regexp.exec were used in the loop to get all matches with groups:
This works now as well, although for newer browsers
str.matchAll is usually more convenient.
We can use
regexp.exec to search from a given position by manually setting
If the regexp has flag
y, then the search will be performed exactly at the position
regexp.lastIndex, not any further.
Let’s replace flag
y in the example above. There will be no matches, as there’s no word at position
That’s convenient for situations when we need to “read” something from the string by a regexp at the exact position, not somewhere further.
regexp.test(str) looks for a match and returns
true/false whether it exists.
An example with the negative answer:
If the regexp has flag
regexp.test looks from
regexp.lastIndex property and updates this property, just like
So we can use it to search from a given position:
If we apply the same global regexp to different inputs, it may lead to wrong result, because
regexp.test call advances
regexp.lastIndex property, so the search in another string may start from non-zero position.
For instance, here we call
regexp.test twice on the same text, and the second time fails:
That’s exactly because
regexp.lastIndex is non-zero in the second test.
To work around that, we can set
regexp.lastIndex = 0 before each search. Or instead of calling methods on regexp, use string methods
str.match/search/..., they don’t use