Fabrício Matté
Fabrício Matté

Reputation: 70139

Best way to store JS Regex capturing groups in array?

Exactly what title asks. I'll provide some examples while explaining my question.

Test string:

var test = "#foo# #foo# bar #foo#";

Say, I want to extract all text between # (all foos but not bar).

var matches = test.match(/#(.*?)#/g);

Using .match as above, it'll store all matches but it'll simply throw away the capturing groups it seems.

var matches2 = /#(.*?)#/g.exec(test);

The .exec method apparently returns only the first result's matched string in the position 0 of the array and my only capturing group of that match in the position 1.

I've exhausted SO, Google and MDN looking for an answer to no avail.

So, my question is, is there any better way to store only the matched capturing groups than looping through it with .exec and calling array.push to store the captured groups?

My expected array for the test above should be:

 [0] => (string) foo
 [1] => (string) foo
 [2] => (string) foo

Pure JS and jQuery answers are accepted, extra cookies if you post JSFiddle with console.log. =]

Upvotes: 16

Views: 12758

Answers (5)

Aadit M Shah
Aadit M Shah

Reputation: 74204

I'm not sure if this is the answer you are looking for but you may try the following code:

var matches = [];

var test = "#foo# #foo# bar #foo#";

test.replace(/#(.*?)#/g, function (string, match) {
    matches.push(match);
});

alert(JSON.stringify(matches));

Hope it helps.

Upvotes: 6

Erik  Reppen
Erik Reppen

Reputation: 4635

In case somebody arrives with a similar need to mine, I needed a matching function for a Django-style URL config handler that could pass path "arguments" to a controller. I came up with this. Naturally it wouldn't work very well if matching '$' but it wouldn't break on '$1.00'. It's a little bit more explicit than necessary. You could just return matchedGroups from the else statement and not bother with the for loop test but ;; in the middle of a loop declaration freaks people out sometimes.

var url = 'http://www.somesite.com/calendar/2014/june/6/';
var calendarMatch = /^http\:\/\/[^\/]*\/calendar\/(\d*)\/(\w*)\/(\d{1,2})\/$/;

function getMatches(str, matcher){
    var matchedGroups = [];
    for(var i=1,groupFail=false;groupFail===false;i++){
        var group = str.replace(matcher,'$'+i);

        groupFailTester = new RegExp('^\\$'+i+'$');

        if(!groupFailTester.test(group) ){
            matchedGroups.push(group);
        }
        else {
            groupFail = true;
        }
    }
    return matchedGroups;
}

console.log( getMatches(url, calendarMatch) );

Upvotes: 1

Prasenjit Kumar Nag
Prasenjit Kumar Nag

Reputation: 13461

You can use .exec too like following to build an array

var arr = [],
    s = "#foo# #bar# #test#",
    re = /#(.*?)#/g,
    item;

while (item = re.exec(s))
    arr.push(item[1]);

alert(arr.join(' '));​

Working Fiddle

Found from Here

Well, it still has a loop, if you dont want a loop then I think you have to go with .replace(). In which case the code will be like

var arr = [];
var str = "#foo# #bar# #test#"
str.replace(/#(.*?)#/g, function(s, match) {
                           arr.push(match);
                        });

Check these lines from MDN DOC which explains your query about howexec updates lastIndex property I think,

If your regular expression uses the "g" flag, you can use the exec method multiple times to find successive matches in the same string.

When you do so, the search starts at the substring of str specified by the regular expression's lastIndex property (test will also advance the lastIndex property).

Upvotes: 19

Leonid
Leonid

Reputation: 3171

data.replace(/.*?#(.*?#)/g, '$1').split(/#/)
No loops, no functions.

Upvotes: 2

kennebec
kennebec

Reputation: 104760

Another thought, though exec is as efficient.

var s= "#foo# #foo# bar #foo#";
s= s.match(/#([^#])*#/g).join('#').replace(/^#+|#+$/g, '').split(/#+/);

Upvotes: 0

Related Questions