Валидиране на низов математически израз

Момчета, работя върху система, която оценява низови математически изрази.

моя клас да извърши изчислението

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.

Има много налични диалекти и няколко страхотни урока, но отговорът на този SO въпрос всъщност показва как да създадете анализатор на математически изрази, който в крайна сметка оценява своя вход.

Можете да проверите (изненадващо малкия) граматичен файл в отговора, но действителното използване е доста просто:

  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.

Можете да пропуснете секцията lexer и да отидете направо към анализатора:

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

ако приемем, че expr вече е дефинирано със сбор, изваждане и т.н.

За любопитна душа -- не "abs(", защото в такъв случай abs ( 5 ) ще даде грешка (невалиден израз).

person greenoldman    schedule 08.12.2013