views:

240

answers:

3

It's my understanding that all three of these lines below should return an ARRAY with 2 results in it. Yet RegExp will only return 1 result no matter how many times the regex repeats in the string.

Can some one explain why? And perhaps suggest how I can get RegExp to give me global results?

//INTPUT: 
    console.log(new RegExp("New York", "gi").exec("New York New York")); 

//OUTPUT: 
["New York"]

//INTPUT: 
    console.log(new RegExp(/New York/gi).exec("New York New York"));

//OUTPUT: 
["New York"]

//INTPUT: 
    console.log("New York New York".match(/New York/gi));

//OUTPUT:
["New York", "New York"]
+2  A: 

This is expected, exec() returns a single match but provides more info about the match than match(). If you just want all the matches, use match(). From JavaScript: The Definitive Guide:

Recall that match() returns an array of matches when passed a global regular expresion. exec(), by contrast, always returns a single match and provides complete information about that match. When exec() is called on a regular epression that has the g flag, it sets the lastIndex property of the matched substring. When exec() is invoked a second time for the same regular expression, it begins its search at the character position indicated by the lastIndex property.

Swingley
+5  A: 

your third example is the best way to get the array of matches.

RegExp.exec actually remembers its position, and returns the next result on subsequent calls:

>>> var v = /new york/gi
>>> v.exec("NEW YORK new york")
["NEW YORK"]
>>> v.exec("NEW YORK new york")
["new york"]
>>> v.exec("NEW YORK new york")
null
Rob Fonseca-Ensor
you could leverage this to build an aray yourself, but it's easier to just call string.match
Rob Fonseca-Ensor
I have an array of keywords that I'm trying to get a count of the number of occurrences in a string. what's the best way to do that?
STHayden
+1  A: 

Swingley, thank you for posting this. I had an issue, recalling a re.exec() in a script. An example of it was:

function test(){
   var str = "id"; 
   var re  = /id/ig;
   alert(re.exec(str));
}

Outputs:
Pass 1: id
Pass 2: null
Pass 3: id
Pass 4: null

Obviously, my real pattern and string was more involved, but the result was all because of what you mentioned. The re was retaining the .lastIndex from the previous call. Setting .lastIndex = 0; after the last .exec() makes it all better :)

I thought redefining the re in the function would reset that value though, but I guess RegExp is storing each pattern in a global variable? I'd like to know how to destroy that at the end of the function (delete re; doesn't work).

vol7ron