Search code examples
c#stringparsingformula

Parse complex formula string with nested parenthesis in C#


I am looking for a way to parse complex VFP calculations strings.

An example of one of these formulas would be :

ABS((ABS(-48) - ABS(245 + 34 - 98))) + ABS(ABS(10 + 9)) > 100

As you can see, I have already substituted all variable patterns with there respective values - my issue is in parsing out the ABS() calls so I can substitute them out with C# Math.Abs().

In my case, I want to receive a list of string:

  • ABS(-48)
  • ABS(245 + 34 -98)
  • ABS(10 + 9)

I thought using regex pattern matching would be the ticket, but I cannot figure out how to define a pattern that would give me (with 100% accuracy) something like "ABS(245 + 34 -98)" out of the original formula.

I would love to either know the pattern I need to use, or see someone else's example of parsing something like this successfully (I have tried many SO solutions that never parse it correctly....), or even better a suggested library that can evaluate (returns true or false) that calculation in as it is (I thought I had it with Datatable.Compute() - but it returns ABS(x) as null....).

Also, so everyone does not comment about it, I did not write these calculations...I am only trying to parse them out in C# wihtout having to change the string formulas that already exist.

Thanks in advance!


Solution

  • If you want to match inmost calls only (not a proper abstract syntax tree):

    I want to receive a list of string:

    • ABS(-48)
    • ABS(245 + 34 -98)
    • ABS(10 + 9)

    you can try regular expression with a pattern like this:

    [A-Za-z]+\s*\([0-9\+\*\-\s]+\)
    

    C# code will be

    using System.Text.RegularExpressions;
    using System.Linq;
    
    ...
    
    string text = "ABS((ABS(-48) - ABS(245 + 34 - 98))) + ABS(ABS(10 + 9)) > 100";
    
    List<string> result = Regex
      .Matches(text, @"[A-Za-z]+\s*\([0-9\/\+\/\*\-\s]+\)")
      .Cast<Match>()
      .Select(match => match.Value)
      .ToList();
    
    Console.WriteLine(string.Join(Environment.NewLine, result));
    

    Output:

    ABS(-48)
    ABS(245 + 34 - 98)
    ABS(10 + 9)
    

    Fiddle