Skip to main content
 首页 » 编程设计

c#之用于验证算术表达式的正则表达式

2024年01月22日27dudu

我有一个算术表达式

string exp = "((2+3.1)/2)*4.456"; 


我想通过使用正则表达式进行验证。该表达式只能包含整数,浮点数,操作数和括号。

我如何生成正则表达式以进行验证,请帮助或提出任何其他验证该字符串的方法。

请您参考如下方法:

使用Perl / PCRE,我们可以借助如下结构的模式来验证这种简单的算术表达式:

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


其中,根据需要定义了 num和 op。例如:

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


这将为我们提供以下工作表达:

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


但是,此类表达式不能与.NET正则表达式一起使用,因为它不支持(递归)后继调用 (?&name)。
而是.NET regex lib为我们提供了其特殊功能: balancing groups。

使用平衡组,我们可以重写 pnum中使用的必需的递归调用,并使用如下结构:

expr = pnum ( op pnum )* (?(p)(?!)) 
pnum = (?> (?<p> \( )* num (?<-p> \) )* ) 


我们在这里所做的是在每个数字前后允许任意数量的可选打开和关闭括号,计算打开括号 (?<p> \( )的总数,从该数字 (?<-p> \) )以及表达式的末尾减去闭合括号。确保开放括号的数量为0 (?(p)(?!))。

(我相信这等效于原始结构,不过我还没有提供任何正式的证据。)

产生以下.NET模式:

(?x) 
^ 
(?> (?<p> \( )* (?>-?\d+(?:\.\d+)?) (?<-p> \) )* ) 
(?>(?: 
    [-+*/] 
    (?> (?<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) 
                ^ 
                (?> (?<p> \( )* (?>-?\d+(?:\.\d+)?) (?<-p> \) )* ) 
                (?>(?: 
                    [-+*/] 
                    (?> (?<p> \( )* (?>-?\d+(?:\.\d+)?) (?<-p> \) )* ) 
                )*) 
                (?(p)(?!)) 
                $ 
            "); 
 
            foreach (var expr in expressions) 
            { 
                Console.WriteLine("Expression: " + expr); 
                Console.WriteLine("    Result: " + (regex.IsMatch(expr) ? "Matched" : "Failed")); 
            } 
        } 
    } 
} 


输出:

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