C # RegEx for nested function

I find it difficult to evaluate the following expression using RegEx in C #.

add(1, 2, sub(4, add(1, 2)), div(4, 2)) 

which will be rated below.

 => add(1, 2, sub(4, 3), 2) => add(1, 2, 1, 2) => 6 

Functions are selected from regular expression expressions, and parameters are selected from any numbers. Thanks in advance.

Here is what I am trying:

 class Program { static Regex extractFuncRegex = new Regex(@"(?<func>add|sub|div)\s*\((?<params>.*)\)$", RegexOptions.ExplicitCapture); static Regex extractArgsRegex = new Regex(@"([^,]+\(.+?\))|([^,]+)"); static void Main(string[] args) { string test = @"add(1, 2, sub(4, add(1, 2)), div(4, 2))"; Console.WriteLine(ParseFunction(test)); Console.ReadLine(); } static string ParseFunction(string expr) { expr = extractFuncRegex.Replace(expr, (m) => { string func = m.Groups["func"].Value; string param = m.Groups["params"].Value; Console.WriteLine("Function: {0}", func); MatchCollection paramCollection = extractArgsRegex.Matches(param); List<string> pa = new List<string>(); foreach (Match item in paramCollection) { string p = item.Groups[0].Value.Trim(); Console.WriteLine("\tParameter: {0}", p); if (extractFuncRegex.IsMatch(p)) p = ParseFunction(p); pa.Add(p); } switch (func) { case "add": float a1 = 0; foreach (string item in pa) a1 += float.Parse(item); return a1.ToString(); case "sub": return (float.Parse(pa[0]) - float.Parse(pa[1])).ToString(); case "div": return (float.Parse(pa[0]) / float.Parse(pa[1])).ToString(); default: return expr; } }); return expr; } } 

If you are debugging, you can see there is a problem for parsing

 sub(4, add(1, 2)) 
+1
source share
1 answer

You have clearly done a good job right now, so I won’t say “don’t use regular expressions, don’t drop them and don’t use anything else” - I’m going to show how you can do your work with minimal changes.

First, change extractFuncRegex to

 @"(?<func>add|sub|div)\s*\((?<params>[^()]*)\)" 

I replaced .* In the params group with [^()]* . this means that it will only correspond to a function call that does not contain any other function calls, because this is the only thing we can work with directly. I also deleted trailing $ to make it work.

Now the trick is to call either ParseFunction or extractFuncRegex.Replace until replacements are made. For example, you could put a call to extractFuncRegex.Replace in a loop like this (untested):

 bool doneWork = true; while (doneWork) { doneWork = false; expr = extractFuncRegex.Replace(expr, (m) => { doneWork = true; ... }); } ... 

Using this, you get a sequence of gradually simplified expressions. At each stage, only the deepest function calls are replaced.

 add(1, 2, sub(4, add(1, 2)), div(4, 2)) |-------- |-------- add(1, 2, sub(4, 3 ), 2 ) |---------------- add(1, 2, 1 , 2 ) |-------------------------------------- 6 
0
source

Source: https://habr.com/ru/post/1273294/


All Articles