1

I am trying to extract the function arguments from my string s

var s = "function (a, b,   c) { return \'hello\'; }";
var re = /^function[^\(]*\(\W*(?:(\w+)[,\s)]*)+\)/g;

console.log( re.exec(s) );

/*
[ 'function (a, b,   c)',
  'c',
  index: 0,
  input: 'function (a, b,   c) { return \'hello\'; }' ]
*/

The problem

It is only capturing c.

Desired output

/*
[ 'function (a, b,   c)',
  'a',
  'b',
  'c',
  index: 0,
  input: 'function (a, b,   c) { return \'hello\'; }' ]
*/

Disclaimer

This code is used in a module and must be accomplished with a single regular expression. Other techniques I've seen on StackOverflow will not work.

Community
  • 1
  • 1
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • 1
    This is a classic [Repeating a Capturing Group vs. Capturing a Repeated Group](http://www.regular-expressions.info/captureall.html) issue. Your previously captured backreference keeps getting overwritten and hence will always show the last argument which is `c` in your case. – Kash Sep 11 '12 at 19:35
  • @Kash, this is very helpful information. I modified my capture group to be `...((?:\w+[,\s]*)+)...` which gets me most of the way. If you post this as an answer, I will mark it as accepted. – Mulan Sep 12 '12 at 04:06

2 Answers2

1

You can't have a variable number of capturing groups within a regular expression. The best you can probably do is:

var s = "function (a, b,   c) { return \'hello\'; }";
s.match(/.*?\((.*)\)/)[1].split(/[,\s]+/);

// returns ["a", "b", "c"]
Andrew Cheong
  • 29,362
  • 15
  • 90
  • 145
ilan berci
  • 3,883
  • 1
  • 16
  • 21
  • @shhac - Please reconsider the guidelines for editing. Capitalization of an insignificant word, removing semicolons at the end of JavaScript statements (which may be, arguably, undesirable: http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascript), and adding extra characters to meet the edit minimum, is discouraged. – Andrew Cheong Sep 11 '12 at 19:37
  • @acheong87 I made my edit at the same time as Rocket's, it was peer-accepted afterwards (unnecessarily) – Paul S. Sep 11 '12 at 19:38
0

I would suggest to divide the task to sub-tasks:

  • Retrieve list of arguments
  • Split retrieved list
  • Compose the result

Like this:

var reFuncDecl = /^function\s*\(([^)]+)\)/g,
    reSplitArg = /[,\s]+/;

function funcInfo(s) {
    var matches = reFuncDecl.exec(s),
    args = matches[1].split(reSplitArg);
    reFuncDecl.lastIndex = 0;
    return {
        declaration: matches[0],
        args: args,
        input: s
    };
}


var s = "function (a, b,   c,d,e,\nf) { return \'hello\'; }",
    info = funcInfo(s);
for(var prop in info) {
    document.write(prop + ': ' + info[prop] + '<br />');
}
console.log(funcInfo(s));​

DEMO

Eugene Naydenov
  • 7,165
  • 2
  • 25
  • 43