6

The Situation

I have a string that I want to match the same capture group multiple times. I need to be able to get at both matches.

Example Code

var curly = new RegExp("{([a-z0-9]+)}", "gi");
var stringTest = "This is a {test} of my {pattern}";

var matched = curly.exec(stringTest);
console.log(matched);

The Problem

Right now, it only shows the first match, not the second.

JSFiddle Link

http://jsfiddle.net/npp8jg39/

Jake
  • 3,673
  • 8
  • 34
  • 51

4 Answers4

9

Try this:

    var curly = /{([a-z0-9]+)}/gi,
        stringTest = "This is a {test} of my {pattern}",
        matched;
    while(matched = curly.exec(stringTest))
        console.log(matched);
user10089632
  • 4,762
  • 1
  • 24
  • 34
Oriol
  • 249,902
  • 55
  • 405
  • 483
  • Note that the regexp must be specified in a separate variable. `while (/{[a-z0-9]+)}/gi.exec(stringTest))` doesnot shift the index and does not end well. – dr jerry Dec 29 '19 at 15:49
2

The exec method must be used in a while loop if you want to treat several results. See the MDN Documentation.

Casimir et Hippolyte
  • 85,718
  • 5
  • 90
  • 121
2

Strings in JavaScript have a match method - you can use this to match all instances of a regular expression, returned as an array:

stringTest.match(curly);

This will return an array of matches:

> ["{test}", "{pattern}"]

To pull the inner values, you can use substr:

var arr = stringTest.match(curly);

arr[0] = arr[0].substr(1, arr[0].length - 2);
> "test"

Or to convert the entire array:

for (var i = 0; i < arr.length; i++)
    arr[i] = arr[i].substr(1, arr[i].length - 2);
> ["test", "pattern"]
James Donnelly
  • 122,518
  • 33
  • 200
  • 204
  • I need to be able to get the string inside the capture group, though. Like "test" and "pattern". – Jake Oct 15 '14 at 21:31
  • +1, could you also include the code to do it with an `exec` loop, for iterative processing? – slezica Oct 15 '14 at 21:32
2

Normally this is done by the RegExp.exec method but you know it's convoluted. Everytime I need to use it i have to look up to remember this stateful operation. It's like you need a state monad or something :)

Anyways. In recent JS engines there is this String.matchAll() which does the same thing in a much sane fashion by returning an iterator object.

var curly = new RegExp("{([a-z0-9]+)}", "gi");
var stringTest = "This is a {test} of my {pattern}";

var matches = [...stringTest.matchAll(curly)];
console.log(matches);

If you need only the capture groups then just map the above result. Let's use Array.from() this time.

var curly = new RegExp("{([a-z0-9]+)}", "gi");
var stringTest = "This is a {test} of my {pattern}";

var matches = Array.from(stringTest.matchAll(curly), m => m[1]);
console.log(matches);
Redu
  • 22,595
  • 5
  • 50
  • 67