验证字符串数学表达式

时间:2013-12-06 11:34:05

标签: c# regex validation evaluation

伙计我正在研究一个评估字符串数学表达式的系统。

我的班级进行计算

public Double Calculate(string argExpression)
{
    //get the user passed string
    string ExpressionToEvaluate = argExpression;

    //pass string in the evaluation object declaration.
    Expression z = new Expression(ExpressionToEvaluate);

    //command to evaluate the value of the **************string expression
    var result = z.Evaluate();
    Double results = Convert.ToDouble(result.ToString());

    return results;
}

我的电话代码。

Double Finalstat = calculator.Calculate(UserQuery); 

直到现在我的表情是

4 + 5 + 69 * (100*3)

然而,在测试期间,我发现表达式也可能会失真(因为它是用户构建的)。 对于像

这样的事情
45+99abs - 778anv

所以我想知道是否有一种方法可以验证用户构建的(表达式),然后再将它发送到类中进行评估?

3 个答案:

答案 0 :(得分:0)

我建议您使用CodeDom,因为它可以完美地进行验证:

            CodeDomProvider provider = CSharpCodeProvider.CreateProvider("C#");
            CompilerParameters options = new CompilerParameters();
            options.GenerateExecutable = false;
            options.GenerateInMemory = true;
            // create code
            string source = "using System;namespace Expression{public static class Expression{public static void Test() {\n";
            source += expression; // your expression
            source +=";}}}";
            // compile
            var result = provider.CompileAssemblyFromSource(options, source);
            if (result.Errors.HasErrors)
                foreach (CompilerError error in result.Errors)
                    ; // use error.Column and .Row to get where error was, use .ErrorText to get actuall message, to example "Unknown variable aaa"

现在必须离开,希望我没有犯错(如果我这样做,有人应该纠正我^^)..直到星期一..

答案 1 :(得分:0)

解析数学表达式最初似乎很容易,但很快变得棘手,尤其是当你使用正则表达式时(这是对你的其他问题的引用)。

使用ANTLR创建一个简单的解析器来验证并最终执行表达式会更容易。 ANTLR是一种非常流行的解析器生成器,甚至可以在ASP.NET MVC中使用。

有许多方言和几个很棒的教程,但the answer to this SO question实际上展示了如何创建最终评估其输入的数学表达式解析器。

您可以在答案中查看(令人惊讶的小)语法文件,但实际使用情况非常简单:

  string expression = "(12.5 + 56 / -7) * 0.5";
  ANTLRStringStream Input = new ANTLRStringStream(expression);  
  ExpressionLexer Lexer = new ExpressionLexer(Input);
  CommonTokenStream Tokens = new CommonTokenStream(Lexer);
  ExpressionParser Parser = new ExpressionParser(Tokens);
  Console.WriteLine(expression + " = " + Parser.parse());

问题可以追溯到2010年,当你需要java从语法中创建解析器文件时。更高版本的ANTLR删除了这一要求。

答案 2 :(得分:0)

使用正则表达式会导致问题,因为您必须验证括号:

abs(sin(log(...)))

你应该解析表达式,而不是仅仅将它与某些模式匹配。编写解析器规则也更清晰,更容易理解。作为奖励,您不仅可以获得验证,还可以获得表达式的评估。我的套件NLT包含了C#所需的一切(包括简单的计算器),并且您希望通过添加abs来增强它。

你可以省略lexer部分,然后直接进入解析器:

expr -> "abs" "(" e:expr ")"  // pattern
        { Math.Abs(e) };      // action

假设已使用求和,减法等定义expr

对于好奇的灵魂 - 不是"abs(",因为在这种情况下abs ( 5 )会给出错误(无效的表达)。