The most surprising behavior of JavaScript regular expression you have ever seen

I’m sure, You might have never noticed this surprising behavior

Yogesh Chavan
Feb 7 · 2 min read

JavaScript regular expression objects are stateful when they have /g or /y flag in the pattern to match.

When you create a regular expression which has /g flag, it maintains the lastIndex property which keeps track of the index where to start finding for the next match. So next time when we start testing using the same pattern, it starts searching from the index it found last match.

Consider, we have a regular expression like this

const pattern = /ab/g;

and you want to find if the pattern is present or not in any of the string passed, we can do like this

console.log(pattern.test('abcd')) // true
console.log(pattern.lastIndex) // 2

But as the lastIndex property is maintained by the regular expression stored in variable pattern which is 0 initially and becomes 2 when it finds the match at 0th position in string abcd, so when next time we call test method, it starts from 2nd position to search for the match and so the match fails.

console.log(pattern.test('abcd')) // false
console.log(pattern.lastIndex) // 0

And as it’s not able to find string ab inside abcd starting from position 2, it resets lastIndex property to 0 so when we again call the method it returns true

console.log(pattern.test('abcd')) // true

This might not be the behavior you expected but this is how regular expression maintains the lastIndex property when either using test() or exec()method.

Suppose you want to find position of all occurrences of vowels in a string, you can do something like this

const source = "This is some text";
const pattern = /[aeiou]/g;
while((result = pattern.exec(source)) !== null) {
console.log("Character " + result[0] + " found at position " + (pattern.lastIndex - 1));
}
/* output:Character i found at position 2
Character i found at position 5
Character o found at position 9
Character e found at position 11
Character e found at position 14
*/

But this may not be the behavior you always want.

So in that case, you can use the match()method of regular expression instead of test() or exec().
If you want to use test()method only then you need to reset the lastIndex to 0 after every search.

const pattern = /ab/g;
console.log(pattern.test('abcd')) // true
pattern.lastIndex = 0;
console.log(pattern.test('abcd')) // true

This is one of the most surprising behavior of regular expression you have ever seen.

That’s it for today. Hope you learned something new today.

Subscribe to get weekly updates directly in your inbox https://subscribe-user.herokuapp.com/

JavaScript in Plain English

Learn the web's most important programming language.

Yogesh Chavan

Written by

Full Stack Developer | Javascript | React | Nodejs. Subscribe to get weekly updates directly in your inbox https://subscribe-user.herokuapp.com/

JavaScript in Plain English

Learn the web's most important programming language.

More From Medium

More from JavaScript in Plain English

More from JavaScript in Plain English

More from JavaScript in Plain English

7 really good reasons not to use TypeScript

More from JavaScript in Plain English

More from JavaScript in Plain English

5 Secret features of JSON.stringify()

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade