Jacob
Jacob

Reputation: 63

Why is this regex matching also words within a non-capturing group?

I have this string (notice the multi-line syntax):

var str = `   Number One: Get this
    Number Two: And this`;

And I want a regex that returns (with match):

[str, 'Get this', 'And this']

So I tried str.match(/Number (?:One|Two): (.*)/g);, but that's returning:

["Number One: Get this", "Number Two: And this"]

There can be any whitespace/line-breaks before any "Number" word.

Why doesn't it return only what is inside of the capturing group? Am I misundersating something? And how can I achieve the desired result?

Upvotes: 6

Views: 64

Answers (3)

guest271314
guest271314

Reputation: 1

Try

  var str = "   Number One: Get this\
    Number Two: And this";
  // `/\w+\s+\w+(?=\s|$)/g` match one or more alphanumeric characters , 
  // followed by one or more space characters ,
  // followed by one or more alphanumeric characters , 
  // if following space or end of input , set `g` flag 
  // return `res` array `["Get this", "And this"]`  
  var res =  str.match(/\w+\s+\w+(?=\s|$)/g);

  document.write(JSON.stringify(res));

Upvotes: 2

ShellFish
ShellFish

Reputation: 4551

Replace and store the result in a new string, like this:

var str = `   Number One: Get this
Number Two: And this`;
var output = str.replace(/Number (?:One|Two): (.*)/g, "$1");
console.log(output);

which outputs:

Get this
And this

If you want the match array like you requested, you can try this:

var getMatch = function(string, split, regex) {
    var match = string.replace(regex, "$1" + split);
    match = match.split(split);
    match = match.reverse();
    match.push(string);
    match = match.reverse();
    match.pop();
    return match;
}

var str = `   Number One: Get this
Number Two: And this`;
var regex = /Number (?:One|Two): (.*)/g;
var match = getMatch(str, "#!SPLIT!#", regex);
console.log(match);

which displays the array as desired:

[ '   Number One: Get this\n    Number Two: And this',
'   Get this',
'\n    And this' ]

Where split (here #!SPLIT!#) should be a unique string to split the matches. Note that this only works for single groups. For multi groups add a variable indicating the number of groups and add a for loop constructing "$1 $2 $3 $4 ..." + split.

Upvotes: 2

ruakh
ruakh

Reputation: 183251

Per the MDN documentation for String.match:

If the regular expression includes the g flag, the method returns an Array containing all matched substrings rather than match objects. Captured groups are not returned. If there were no matches, the method returns null.

(emphasis mine).

So, what you want is not possible.

The same page adds:

  • if you want to obtain capture groups and the global flag is set, you need to use RegExp.exec() instead.

so if you're willing to give on using match, you can write your own function that repeatedly applies the regex, gets the captured substrings, and builds an array.


Or, for your specific case, you could write something like this:

var these = str.split(/(?:^|\n)\s*Number (?:One|Two): /);
these[0] = str;

Upvotes: 4

Related Questions