Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript regex back references returning an array of matches from single capture group (multiple groups)

I'm fairly sure after spending the night trying to find an answer that this isn't possible, and I've developed a work around - but, if someone knows of a better method, I would love to hear it...

I've gone through a lot of iterations on the code, and the following is just a line of thought really. At some point I was using the global flag, I believe, in order for match() to work, and I can't remember if it was necessary now or not.

var str = "@abc@def@ghi&jkl";
var regex = /^(?:@([a-z]+))?(?:&([a-z]+))?$/;

The idea here, in this simplified code, is the optional group 1, of which there is an unspecified amount, will match @abc, @def and @ghi. It will only capture the alpha characters of which there will be one or more. Group 2 is the same, except matches on & symbol. It should also be anchored to the start and end of the string.

I want to be able to back reference all matches of both groups, ie:

result = str.match(regex);
alert(result[1]); //abc,def,ghi
alert(result[1][0]); //abc
alert(result[1][1]); //def
alert(result[1][2]); //ghi
alert(result[2]); //jkl

My mate says this works fine for him in .net, unfortunately I simply can't get it to work - only the last matched of any group is returned in the back reference, as can be seen in the following:

(additionally, making either group optional makes a mess, as does setting global flag)

var str = "@abc@def@ghi&jkl";
var regex = /(?:@([a-z]+))(?:&([a-z]+))/;

var result = str.match(regex);

alert(result[1]); //ghi
alert(result[1][0]); //g
alert(result[2]); //jkl

The following is the solution I arrived at, capturing the whole portion in question, and creating the array myself:

var str = "@abc@def@ghi&jkl";
var regex = /^([@a-z]+)?(?:&([a-z]+))?$/;

var result = regex.exec(str);

alert(result[1]); //@abc@def@ghi
alert(result[2]); //jkl

var result1 = result[1].toString();
result[1] = result1.split('@')

alert(result[1][1]); //abc
alert(result[1][2]); //def
alert(result[1][3]); //ghi
alert(result[2]); //jkl
like image 234
Patrick Avatar asked Oct 07 '22 23:10

Patrick


1 Answers

That's simply not how .match() works in JavaScript. The returned array is an array of simple strings. There's no "nesting" of capture groups; you just count the ( symbols from left to right.

The first string (at index [0]) is always the overall matched string. Then come the capture groups, one string (or null) per array element.

You can, as you've done, rearrange the result array to your heart's content. It's just an array.

edit — oh, and the reason your result[1][0] was "g" is that array indexing notation applied to a string gets you the individual characters of the string.

like image 120
Pointy Avatar answered Oct 13 '22 12:10

Pointy