Accessing captured groups within JavaScript can be a bit clunky:
var result = selector.match(/^((?:[~+>] )?.*?)(?: |$)(.*)$/i).slice(1);
var token = result[0];
var remainder = result[1];
I prefer to capture groups by converting them to named properties of an anonymous object. Below is an example of a function I put together as part of a CSS selection engine I am working on. Leveraging the Function object’s ‘apply’ method, it’s possible to pass the elements of the resulting captured groups array to an interim anonymous function. The arguments of said function get packaged up in an object, as named properties. Ultimately, the anonymous object is returned through to the original calling client code.
var getToken = function(selector) {
return function(token, remainder) {
return {token: token, remainder: remainder};
// (?: ) non capturing group
// slice the first element out of the array
// which is the original subject string
}.apply(null, selector.match(/^((?:[~+>] )?.*?)(?: |$)(.*)$/i).slice(1));
};
// this is a much cleaner way to get at the pertinent data:
var result = getToken('#someId .someClass > li');
console.log(result.token); // #someId
console.log(result.remainder); // .someClass > li
However, this is really only applicable in cases where you know ahead of time what your regular expression is going to be and you know how you want your captured groups named. For a more reusable solution, consider the following:
var namedGroups = function(regex, callback) {
return function(subject) {
return callback.apply(null, subject.match(regex).slice(1));
}
}
// usage:
var regex = /^((?:[~+>] )?.*?)(?: |$)(.*)$/i;
var getToken = namedGroups(regex, function(token, remainder) {
return {token: token, remainder: remainder};
});
The beauty of this reusable method is that you can decide what you want to do with the captured groups before returning to the original client code. Anyway, let me know what you think and share your techniques with the rest of us!