8

I'm confused on how this is possible...

var matcher = new RegExp("d", "gi");
matcher.test(item)

The code above contains the following values

item = "Douglas Enas"
matcher = /d/gi

Yet when I run the matcher.test function back to back I get true for the first run and false for the second run.

matcher.test(item) // true
matcher.test(item) // false

If I use a regexp literal such as

/d/gi.test("Douglas Enas") 

and run it back to back in chrome I get true both times. Is there an explanation for this?

Sample of a back to back run in chrome console creating a regexp object using constructor

matcher = new RegExp("d","gi")
/d/gi

matcher.test("Douglas Enas")
true

matcher.test("Douglas Enas")
false

matcher
/d/gi

Sample using back to back calls on literal

/d/gi.test("Douglas Enas")
true

/d/gi.test("Douglas Enas")
true

The reason for this question if because using the RegExp constructor and the test function against a list of values I'm losing matches... However using the literal I'm getting back all the values I expect

UPDATE

                        var suggestions = [];

                        ////process response  
                        $.each(responseData, function (i, val)
                        {
                            suggestions.push(val.desc);
                        });


                        var arr = $.grep(suggestions, function(item) {
                            var matcher = new RegExp("d", "gi");
                            return matcher.test(item);
                        });

Moving the creation of the matcher inside the closure included the missing results. the "d" is actually a dynamically created string but I used "d" for simplicity sake. I'm still not sure now creating a new expression every time I do the test when I am iterating over the suggestions array would inadvertently exclude results is a little confusing still, and probably has something to do with the advancement of the match test

NullUserException
  • 83,810
  • 28
  • 209
  • 234
DRobertE
  • 3,478
  • 3
  • 26
  • 43
  • I cant reproduce the issue, I get true everytime for this code : var matcher = new RegExp("d", "gi"); matcher.test("Douglas Enas"); – Andrew Magill Nov 21 '12 at 19:24

3 Answers3

10

From RegExp.test():

test called multiple times on the same global regular expression instance will advance past the previous match.

So basically when you have an instance of RegExp, each call to test advances the matcher. Once you've found the first d, it will look beyond that and try to find another d. Well, there are none anymore, so it returns false.

On the other hand, when you do:

/d/gi.test("Douglas Enas") 

You create a new RegExp instance every time on the spot, so it will always find that first d (and thus return true).

NullUserException
  • 83,810
  • 28
  • 209
  • 234
  • So in the case of using it with a grep in jquery `var matcher = new RegExp("d", "gi"); var arr = $.grep(suggestions, function(item) { return matcher.test(item); });` How would that exclude matching values? – DRobertE Nov 21 '12 at 19:28
  • ah I moved the creation of the regex inside the closure and it included the missing values... var arr = $.grep(suggestions, function(item) { var matcher = new RegExp("d", "gi"); return matcher.test(item); }); – DRobertE Nov 21 '12 at 19:31
0

According to Mozilla Developer Network,

As with exec (or in combination with it), test called multiple times on the same global regular expression instance will advance past the previous match.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test

Aaron Kurtzhals
  • 2,036
  • 3
  • 17
  • 21
0

I can't find the link ATM, but as I recall, this is a known issue with the test method in combination with a g pattern: the match position isn't "forgotten" somehow. Either drop the global flag and/or use the .match method, and it'll work just fine.

Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149