When JavaScript regex can surprise you - a silly bug story
Tags: javascript, regex
Published: 2023-02-15 09:30:59

---
title: When JavaScript regex can surprise you - a silly bug story
published: true
date: 2023-02-15 09:25:00 UTC
tags: javascript,regex
canonical_url: https://banach.net.pl/posts/2023/when-javascript-regex-can-surprise-you-a-silly-bug-story/
---

Recently one of my customers let me know that they have probably a bug in their app. They want me to look into it - so I jump into “Sherlock, the bug hunter” mode and start snooping!

The misbehaving feature was some kind of search. It takes an input, a Javascript regular expression and as an output returns _true_ if regex was satisfied - and _false_ otherwise.

The feature was pretty simple on the code side - the search function looked similar to the one below:

```javascript
var search = function(regex, text) {
    if (regex && regex.test(text)) {
        return true;
    }
    return false;
}
```

So we can see that the heart of it was a simple `regex.test` call.

The bug report stated that misbehaving example was regex `/pony/g` and text `this is a pony and not a horse` - we have 100% sure that `pony` is in this sentence. To check if everything was working correctly I opened console in Chrome Developer Tools, loaded the search function and check its result:

```javascript
// Below returns true
search(/pony/g, "this is a pony and not a horse"); 
// this also returns true!
search(/pony/g, "this is a pony and not a horse"); 
// ... five runs later
// eh? still returns true!
search(/pony/g, "this is a pony and not a horse"); 
```

What is going on?! Every run of this function returns the correct and expected value.

But wait… the `regex` and `text` was passed using variables from _somewhere else_. Let’s put them in the variables and try to run the function multiple times again:

```javascript
var regex = /pony/g
var text = "this is a pony and not a horse";
search(regex, pony); // returns true as expected
search(regex, pony); // returns false :O
search(regex, pony); // returns true - what a trickery!
search(regex, pony); // returns false - wut?!
```

And now we have a problem - despite the fact we should get `true` every time we sometimes get `false` instead.

The answer to this weird behaviour is in the… documentation. Quick look at the [RegExp.prototype.test() on mdn web docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test)and we have found the culprit:

> JavaScript RegExp objects are stateful when they have the global or sticky flags set (e.g., `/foo/g` or `/foo/y`). They store a `lastIndex` from the previous match

And the `latIndex` property is described as:

> The `lastIndex` data property of a RegExp instance specifies the index at which to start the next match.

We have the global option in our regex - and that was the reason that it behaves in a not expected manner. Similar results will be if our test text were _this is a pony and second pony_ - it will give us `true` for the first and the second search (as we have two ponies!) and `false` for the third one.

The solution for this issue was simply to reset the `lastIndex` property of regex if something was found

```javascript
var search = function(regex, text) {
    if (regex && regex.test(text)) {
        // reset lastIndex property to make sure 
        // that next test will start from beginning
        regex.lastIndex = 0; 
        return true;
    }
    return false;
}
```

That’s all folks! One line, resetting one property, is all that was needed to fix the issue.

What is the takeaway from this issue? When in doubt and especially when working with regexes - read documentation. It can save you a lot of time. :-)