Regex для сопоставления функций и захвата их аргументов
Я работаю над калькулятором, и он принимает строковые выражения и оценивает их. У меня есть функция, которая ищет выражение для математических функций с использованием Regex, получает аргументы, ищет имя функции и оценивает его. У меня проблемы с тем, что я могу сделать это только, если я знаю, сколько аргументов будет, я не могу понять Regex правильно. И если я просто разделю содержимое(
а также)
символы по,
символ, то я не могу иметь другие вызовы функций в этом аргументе.
Вот образец соответствия функции:\b([a-z][a-z0-9_]*)\((..*)\)\b
Он работает только с одним аргументом. Могу ли я создать группу для каждого аргумента, исключая аргументы внутри вложенных функций? Например, это будет соответствовать:func1(2 * 7, func2(3, 5))
и создать группы захвата для:2 * 7
а такжеfunc2(3, 5)
Вот функция, которую я использую для оценки выражения:
/// <summary>
/// Attempts to evaluate and store the result of the given mathematical expression.
/// </summary>
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<string> args = new List<string>();
List<double> argVals = new List<double>();
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 < 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 > 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 ---- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
/// <summary>
/// The pattern used for function calls.
/// </summary>
public static Regex PatternFunc = new Regex(@"([a-z][a-z0-9_]*)\((..*)\)");
Как вы можете видеть, есть довольно неудачная попытка построить регулярное выражение для соответствия аргументам. Не работает
Все, что я пытаюсь сделать, это извлечь2 * 7
а такжеfunc2(3, 5)
из выраженияfunc1(2 * 7, func2(3, 5))
но это должно работать и для функций с различным количеством аргументов. Если есть способ сделать это без использования Regex, это тоже хорошо.