Проверка строкового математического выражения

Ребята, я работаю над системой, которая оценивает строковое математическое выражение.

мой класс для выполнения расчета

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

Поэтому я хотел знать, есть ли способ проверить построенное пользователем (выражение) перед отправкой его для оценки в классе?


person Anoushka Seechurn    schedule 06.12.2013    source источник
comment
Примечание: вам не нужно делать string ExpressionToEvaluate = argExpression;, просто сделайте Expression z = new Expression(argExpression);   -  person dav_i    schedule 06.12.2013
comment
@dav_i, да, я знаю. Показанные коды не являются полными. Строка ExpressionToEvaluate используется в другой части моей программы. Спасибо.   -  person Anoushka Seechurn    schedule 06.12.2013
comment
Разбор математических выражений с использованием регулярных выражений сначала кажется простым, но очень быстро становится сложным. Было бы проще создать простой синтаксический анализатор с использованием ANTLR для проверки и, в конечном итоге, выполнения ваших выражений.   -  person Panagiotis Kanavos    schedule 06.12.2013


Ответы (3)


Я бы посоветовал вам использовать 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"

Придется уйти сейчас, надеюсь, я не наделал ошибок (если ошибся, кто-то должен меня поправить ^^).. до понедельника..

person Sinatr    schedule 06.12.2013

Разбор математических выражений сначала кажется простым, но очень быстро становится сложным, особенно когда вы используете регулярные выражения (это ссылка на другие ваши вопросы).

Проще создать простой синтаксический анализатор с помощью ANTLR для проверки и, в конечном итоге, выполнения ваших выражений. ANTLR — очень популярный генератор синтаксических анализаторов, который используется даже в ASP.NET MVC.

Доступно много диалектов и несколько отличных руководств, но ответ на этот ТАК вопрос на самом деле показывает, как создать анализатор математических выражений, который в конечном итоге оценивает свои входные данные.

Вы можете проверить (на удивление маленький) файл грамматики в ответе, но фактическое использование довольно просто:

  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 удалили это требование.

person Panagiotis Kanavos    schedule 06.12.2013

С регулярными выражениями у вас возникнет проблема из-за простого факта, что вам нужно проверить круглые скобки:

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

Вы должны анализировать выражение, а не просто сопоставлять его с каким-то шаблоном. Написание правил парсера также намного чище и проще для понимания. В качестве бонуса вы получите не только проверку, но и оценку выражения. Мой пакет NLT содержит все необходимое для C# (в него уже включен простой калькулятор), и, скажем, вы бы хотели бы улучшить его, добавив abs.

Вы можете опустить раздел лексера и сразу перейти к парсеру:

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

предполагая, что expr уже определено с суммой, вычитанием и так далее.

Для любознательных -- не "abs(", потому что в таком случае abs ( 5 ) выдаст ошибку (недопустимое выражение).

person greenoldman    schedule 08.12.2013