RegExp spec question

# Alex Vincent (11 years ago)
r = /\u0020+$/g; p = r.exec("  "); q = r.exec("  "); JSON.stringify([p, q])
// "[[\"  \"],null]"

Why does calling exec the second time generate null? When I try the regular expression without the /g flag, I get:

// "[[\"  \"],[\"  \"]]"
# Andrea Giammarchi (11 years ago)

expected by specs ... try this

r = /\u0020+$/g; p = r.exec("  "); r.lastIndex = 0; q = r.exec("  ");
alert(JSON.stringify([p, q]))

and you are good to go

... without resetting lastIndex, you can also use " ".replace(r, 'whatever') and it's going to work every time.

Have a look at these slides to know more about JS RegExp

WebReflection/talks/tree/master/BerlinJS

# Axel Rauschmayer (11 years ago)

Yes, the /g flag is confusing, because the regular expression kind of turns into an iterator. I’d much prefer an actual iterator-based API that doesn’t mutate the regular expression.

# Frankie Bagnardi (11 years ago)

You could wrap it in an iterator :-)

www.es6fiddle.net/hxoczoqg

function* match(regex, haystack){
  var {source, ignoreCase} = regex;
  var newRegex = new RegExp(source, ignoreCase ? 'gi' : 'g');
  var m = null;
  while (m = newRegex.exec(haystack)) {
  yield m;
  }
}

var input = "I have 5 dogs, 3 cats, and 49 ants.";

for (let num of match(/\d+/, input)) {
console.log(num);
}
# Andrea Giammarchi (11 years ago)

you can also use this code ... like today, with every browser, and right away ...


function match(regex, haystack){
  var result = [], g = regex.global, match;
  do { match = regex.exec(haystack) }
  while(match && result.push(match) && g);
  if (!g) regex.lastIndex = 0;
  return result;
}

var input = "I have 5 dogs, 3 cats, and 49 ants.";

match(/\d+/, input)
match(/\d+/g, input)

Best

# Виктор Мухачев (11 years ago)

function* match(regex, haystack){ var {source, ignoreCase} = regex; var newRegex = new RegExp(source, ignoreCase ? 'gi' : 'g'); var m = null; while (m = newRegex.exec(haystack)) { yield m; } }

this code is not best in that case:

var regex = /\d+/;

var first = match(regex, "1 2 3 4"); var second = match(regex, "1 2 3 4"); first.next(); second.next(); // ?