6

I have a very strage problem:

var cat = [ { slug: "test/foo", id: 1}, { slug: "test/bar", id: 1}];
var searchreg = new RegExp("test","g");

cat.forEach(function(item){
  if(searchreg.test(item.slug)){
    console.log(item);
  } 
});

This should print me both items out of "cat". But I only get the first. If I add more items I only get every 2nd (start with the first).

I get it woking with:

var cat = [ { slug: "test/foo", id: 1}, { slug: "test/bar", id: 1}];

cat.forEach(function(item){
  var searchreg = new RegExp("test","g");
  if(searchreg.test(item.slug)){
    console.log(item);
  } 
});

But I don't understand why this don't work (Chrome) - anyone a Idea?

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
mdunisch
  • 3,627
  • 5
  • 25
  • 41
  • 1
    FWIW, a simpler, more direct way to create that regex is `var searchreg = /test/g;` (or of course, per my answer, leave out the `g`). It's also worth mentioning you don't actually need regex for that, `if (item.slug.indexOf("test") !== -1)` would also work. – T.J. Crowder Jun 06 '14 at 15:03

1 Answers1

16

It's because of the g ("global") flag. RegExp instances have state when you use the g flag: They remember where the last match they saw was, so they can continue from that point (for instance, if you're using them in a loop). (Yes, this is not the best design it could have had.) So the first time, it finds test in the string (and notes that it's not at the end of the string); the second time, it tries to find test continuing in the previous string from the previous location, and of course doesn't find it. The third time, since it knows it ran out of input last time, it looks at the input again.

In your case, since you don't need to search further than the first instance, simply remove the g flag:

var searchreg = /test/; // That's a regex literal, basically: ... = new RegEx("test")

Alternately, you could reset it by assigning 0 to its lastIndex property:

searchreg.lastIndex = 0;
if (searchreg.test(item.slug))

Or, in this specific use case, you don't need regex at all:

if (item.slug.indexOf("test") !== -1) {
    // It has "test" in the slug
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 3
    You can "reset" a global regex by setting its `lastIndex` property to 0. Then again, you should question why you're using a global regex in the first place... – MaxArt Jun 06 '14 at 15:05
  • 1
    Oh thank you - that made it clear: the g-flag :-) i really dont need /g, its just there from copy-paste from another code. So i remove /g and it works perfect! About indexOf: I have a more complex regular expression, i just choose "test" for a simple example. – mdunisch Jun 06 '14 at 15:08
  • Helpful detailed answer +1 :) – zx81 Jun 06 '14 at 21:28
  • Another 30 minutes wasted, thanks for this. – nlhnt Mar 14 '23 at 23:27