title: Regex for matching Functions and Capturing their Arguments
body: <p>I'm working on a calculator and it takes string expressions and evaluates them. I have a function that searches the expression for math functions using Regex, retrieves the arguments, looks up the function name, and evaluates it. What I'm having problem with is that I can only do this if I know how many arguments there are going to be, I can't get the Regex right. And if I just split the contents of the <code>(</code> and <code>)</code> characters by the <code>,</code> character then I can't have other function calls in that argument.</p>
  
  <p>Here is the function matching pattern: <code>\b([a-z][a-z0-9_]*)\((..*)\)\b</code></p>
  
  <p>It only works with one argument, have can I create a group for every argument excluding the ones inside of nested functions? For example, it would match: <code>func1(2 * 7, func2(3, 5))</code> and create capture groups for: <code>2 * 7</code> and <code>func2(3, 5)</code></p>
  
  <p>Here the function I'm using to evaluate the expression:</p>
  
  <pre><code>    /// &lt;summary&gt;
      /// Attempts to evaluate and store the result of the given mathematical expression.
      /// &lt;/summary&gt;
      public static bool Evaluate(string expr, ref double result)
      {
          expr = expr.ToLower();
  
          try
          {
              // Matches for result identifiers, constants/variables objects, and functions.
              MatchCollection results = Calculator.PatternResult.Matches(expr);
              MatchCollection objs = Calculator.PatternObjId.Matches(expr);
              MatchCollection funcs = Calculator.PatternFunc.Matches(expr);
  
              // Parse the expression for functions.
              foreach (Match match in funcs)
              {
                  System.Windows.Forms.MessageBox.Show("Function found. - " + match.Groups[1].Value + "(" + match.Groups[2].Value + ")");
  
                  int argCount = 0;
                  List&lt;string&gt; args = new List&lt;string&gt;();
                  List&lt;double&gt; argVals = new List&lt;double&gt;();
                  string funcName = match.Groups[1].Value;
  
                  // Ensure the function exists.
                  if (_Functions.ContainsKey(funcName)) {
                      argCount = _Functions[funcName].ArgCount;
                  } else {
                      Error("The function '"+funcName+"' does not exist.");
                      return false;
                  }
  
                  // Create the pattern for matching arguments.
                  string argPattTmp = funcName + "\\(\\s*";
  
                  for (int i = 0; i &lt; argCount; ++i)
                      argPattTmp += "(..*)" + ((i == argCount - 1) ? ",":"") + "\\s*";
                  argPattTmp += "\\)";
  
                  // Get all of the argument strings.
                  Regex argPatt = new Regex(argPattTmp);
  
                  // Evaluate and store all argument values.
                  foreach (Group argMatch in argPatt.Matches(match.Value.Trim())[0].Groups)
                  {
                      string arg = argMatch.Value.Trim();
                      System.Windows.Forms.MessageBox.Show(arg);
  
                      if (arg.Length &gt; 0)
                      {
                          double argVal = 0;
  
                          // Check if the argument is a double or expression.
                          try {
                              argVal = Convert.ToDouble(arg);
                          } catch {
                              // Attempt to evaluate the arguments expression.
                              System.Windows.Forms.MessageBox.Show("Argument is an expression: " + arg);
  
                              if (!Evaluate(arg, ref argVal)) {
                                  Error("Invalid arguments were passed to the function '" + funcName + "'.");
                                  return false;
                              }
                          }
  
                          // Store the value of the argument.
                          System.Windows.Forms.MessageBox.Show("ArgVal = " + argVal.ToString());
                          argVals.Add(argVal);
                      }
                      else
                      {
                          Error("Invalid arguments were passed to the function '" + funcName + "'.");
                          return false;
                      }
                  }
  
                  // Parse the function and replace with the result.
                  double funcResult = RunFunction(funcName, argVals.ToArray());
                  expr = new Regex("\\b"+match.Value+"\\b").Replace(expr, funcResult.ToString());
              }
  
              // Final evaluation.
              result = Program.Scripting.Eval(expr);
          }
          catch (Exception ex)
          {
              Error(ex.Message);
              return false;
          }
  
          return true;
      }
  
      ////////////////////////////////// ---- PATTERNS ---- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  
      /// &lt;summary&gt;
      /// The pattern used for function calls.
      /// &lt;/summary&gt;
      public static Regex PatternFunc = new Regex(@"([a-z][a-z0-9_]*)\((..*)\)");
  </code></pre>
  
  <p>As you can see, there is a pretty bad attempt at building a Regex to match the arguments. It doesn't work.</p>
  
  <p>All I am trying to do is extract <code>2 * 7</code> and <code>func2(3, 5)</code> from the expression <code>func1(2 * 7, func2(3, 5))</code> but it must work for functions with different argument counts as well. If there is a way to do this without using Regex that is also good.</p>