Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript RegExp non-capturing groups

I am writing a set of RegExps to translate a CSS selector into arrays of ids and classes.

For example, I would like '#foo#bar' to return ['foo', 'bar'].

I have been trying to achieve this with

"#foo#bar".match(/((?:#)[a-zA-Z0-9\-_]*)/g)

but it returns ['#foo', '#bar'], when the non-capturing prefix ?: should ignore the # character.

Is there a better solution than slicing each one of the returned strings?

like image 736
Alexandre Kirszenberg Avatar asked Jun 02 '12 18:06

Alexandre Kirszenberg


3 Answers

It matches #foo and #bar because the outer group (#1) is capturing. The inner group (#2) is not, but that' probably not what you are checking.

If you were not using global matching mode, an immediate fix would be to use (/(?:#)([a-zA-Z0-9\-_]*)/ instead.

With global matching mode the result cannot be had in just one line because match behaves differently. Using regular expression only (i.e. no string operations) you would need to do it this way:

var re = /(?:#)([a-zA-Z0-9\-_]*)/g;
var matches = [], match;
while (match = re.exec("#foo#bar")) {
    matches.push(match[1]);
}

See it in action.

like image 158
Jon Avatar answered Sep 30 '22 00:09

Jon


The lookbehind assertion mentioned some years ago by mVChr is added in ECMAScript 2018. This will allow you to do this:

'#foo#bar'.match(/(?<=#)[a-zA-Z0-9\-_]*/g) (returns ["foo", "bar"])

(A negative lookbehind is also possible: use (?<!#) to match any character except for #, without capturing it.)

like image 33
user125661 Avatar answered Sep 30 '22 02:09

user125661


You could use .replace() or .exec() in a loop to build an Array.

With .replace():

var arr = [];
"#foo#bar".replace(/#([a-zA-Z0-9\-_]*)/g, function(s, g1) {
                                               arr.push(g1);
                                          });

With .exec():

var arr = [],
    s = "#foo#bar",
    re = /#([a-zA-Z0-9\-_]*)/g,
    item;

while (item = re.exec(s))
    arr.push(item[1]);
like image 41
user1106925 Avatar answered Sep 30 '22 00:09

user1106925