Tuesday, 19 September 2017

c# - Regular expression for validating arithmetic expression

Using Perl/PCRE we could verify such simple arithmetic expressions with help of a pattern structured like:


expr = pnum ( op pnum )*
pnum = num | \( expr \)

Where num and op defined as required. For example:


num = -?+\d++(?:\.\d++)?+
op = [-+*/]

Which would give us the following working expression:


(?x)^ (?&expr) $
(?(DEFINE)
(? (?&pnum) (?: (?&op) (?&pnum) )*+ )
(? (?> (?&num) | \( (?&expr) \) ) )
(? -?+\d++(?:\.\d++)?+ )
(? [-+*/] )
)

But such expressions could not be used with .NET regex as it does not support (recursive) suppatern calls (?&name).
Instead .NET regex lib offers us its special feature: balancing groups.


With balancing groups we could rewrite the required recursive call used in pnum, and use a structure like this instead:


expr = pnum ( op pnum )* (?(p)(?!))
pnum = (?> (?

\( )* num (?<-p> \) )* )


What we've done here is to allow any number of optional opening and closing paranthesis before and after every number, counting the total number of open parentheses (?

\( ), subtracting closing parentheses from that number (?<-p> \) ) and at the end of the expression make sure that the number of open parentheses is 0 (?(p)(?!)).


(I believe this is equivalent to the original structure, altho I haven't made any formal proof.)


Resulting in the following .NET pattern:


(?x)
^
(?> (?

\( )* (?>-?\d+(?:\.\d+)?) (?<-p> \) )* )
(?>(?:
[-+*/]
(?> (?

\( )* (?>-?\d+(?:\.\d+)?) (?<-p> \) )* )
)*)
(?(p)(?!))
$


C# Example:


using System;
using System.Text.RegularExpressions;
namespace RegexTest
{
class Program
{
static void Main(string[] args)
{
var expressions = new string[] {
"((2+3.1)/2)*4.456",
"1",
"(2)",
"2+2",
"(1+(2+3))",
"-2*(2+-2)",
"1+(3/(2+7-(4+3)))",
"1-",
"2+2)",
"(2+2",
"(1+(2+3)",
};
var regex = new Regex(@"(?x)
^
(?> (?

\( )* (?>-?\d+(?:\.\d+)?) (?<-p> \) )* )
(?>(?:
[-+*/]
(?> (?

\( )* (?>-?\d+(?:\.\d+)?) (?<-p> \) )* )
)*)
(?(p)(?!))
$
");
foreach (var expr in expressions)
{
Console.WriteLine("Expression: " + expr);
Console.WriteLine(" Result: " + (regex.IsMatch(expr) ? "Matched" : "Failed"));
}
}
}
}


Output:


Expression: ((2+3.1)/2)*4.456
Result: Matched
Expression: 1
Result: Matched
Expression: (2)
Result: Matched
Expression: 2+2
Result: Matched
Expression: (1+(2+3))
Result: Matched
Expression: -2*(2+-2)
Result: Matched
Expression: 1+(3/(2+7-(4+3)))
Result: Matched
Expression: 1-
Result: Failed
Expression: 2+2)
Result: Failed
Expression: (2+2
Result: Failed
Expression: (1+(2+3)
Result: Failed

No comments:

Post a Comment

casting - Why wasn&#39;t Tobey Maguire in The Amazing Spider-Man? - Movies &amp; TV

In the Spider-Man franchise, Tobey Maguire is an outstanding performer as a Spider-Man and also reprised his role in the sequels Spider-Man...