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

时间:2012-02-25 10:43:05

标签: c# regex

我有一个算术表达式

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

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

如何生成正则表达式以验证请帮助或建议任何其他方式来验证该字符串。

2 个答案:

答案 0 :(得分:7)

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

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

根据需要定义numop的位置。例如:

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

这会给我们以下工作表达式:

(?x)^ (?&expr) $

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

但是这样的表达式不能与.NET正则表达式一起使用,因为它不支持(递归)支持调用(?&name)。 相反,.NET正则表达式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

答案 1 :(得分:1)

您可以使用fslex / fsyacc在F#中编写一个简单的词法分析器。以下是一个非常接近您要求的示例:http://blogs.msdn.com/b/chrsmith/archive/2008/01/18/fslex-sample.aspx