У меня есть выражение, которое я хочу проанализировать, чтобы получить список всех используемых параметров.

Например: «X + 5 / (Y - 1)» должен дать мне следующий результат: X, Y

Я уже использую NCalc в своем проекте; так можно ли использовать NCalc для получения параметров, используемых в выражении?

Согласно этой записи обсуждения (https://ncalc.codeplex.com/discussions/361959) это так, но я не совсем понимаю ответ.

9
Preli 11 Апр 2014 в 17:09

3 ответа

Лучший ответ

Из обсуждения / ответа здесь: http://ncalc.codeplex.com/discussions/360990

Реализация, которую я тестировал и работаю (для предоставленного вами примера выражения), заключается в реализации LogicalExpressionVisitor и записи параметров по мере их нахождения:

class ParameterExtractionVisitor : LogicalExpressionVisitor
{
    public HashSet<string> Parameters = new HashSet<string>();

    public override void Visit(NCalc.Domain.Identifier function)
    {
        //Parameter - add to list
        Parameters.Add(function.Name);
    }

    public override void Visit(NCalc.Domain.UnaryExpression expression)
    {
        expression.Expression.Accept(this);
    }

    public override void Visit(NCalc.Domain.BinaryExpression expression)
    {
        //Visit left and right
        expression.LeftExpression.Accept(this);
        expression.RightExpression.Accept(this);
    }

    public override void Visit(NCalc.Domain.TernaryExpression expression)
    {
        //Visit left, right and middle
        expression.LeftExpression.Accept(this);
        expression.RightExpression.Accept(this);
        expression.MiddleExpression.Accept(this);
    }

    public override void Visit(Function function)
    {
        foreach (var expression in function.Expressions)
        {
            expression.Accept(this);
        }
    }

    public override void Visit(LogicalExpression expression)
    {

    }

    public override void Visit(ValueExpression expression)
    {

    }
}

Тогда вы могли бы использовать его как:

var expression = NCalc.Expression.Compile("2 * [x] ^ 2 + 5 * [y]", false);

ParameterExtractionVisitor visitor = new ParameterExtractionVisitor();
expression.Accept(visitor);

var extractedParameters = visitor.Parameters;

foreach (var param in extractedParameters)
    Console.WriteLine(param);

Это выводит для меня «x» и «y».

Обратите внимание на использование HashSet в ParameterExtractionVisitor. Это потому, что если ваше выражение содержит одну и ту же переменную более одного раза (например: "[x] + [x]"), оно будет добавлено дважды. Если вы хотите сохранять запись каждый раз, когда используется одна и та же переменная, замените HashSet на List.


Тем не менее, у меня очень мало опыта работы с NCalc, поэтому моя реализация переопределенных методов LogicalExpressionVisitor является предположениями . Когда я переопределил метод void Visit(ValueExpression expression) с помощью expression.Accept(this), это привело к StackOverflowException. Поэтому я просто оставил реализацию пустой , и она казалась работающей. Поэтому я предлагаю вам отнестись к моему ответу с очень большой долей скептицизма. Ваш опыт может отличаться, и я не могу сказать, работает ли это для всех типов выражений.

12
Todd Menier 26 Май 2020 в 16:30

У меня это работает. Ваш пробег может отличаться.

   public List<string> GetParameters(string expression) {
       List<string> parameters = new List<string>();
       Random random = new Random();
       NCalc.Expression e = new NCalc.Expression(expression);

       e.EvaluateFunction += delegate(string name, NCalc.FunctionArgs args) {
           args.EvaluateParameters();
           args.Result = random.Next(0, 100);
       };
       e.EvaluateParameter += delegate(string name, NCalc.ParameterArgs args) {
           parameters.Add(name);
           args.Result = random.Next(0, 100);
       };
       try {
           e.Evaluate();
           }
       catch {
            }
       return parameters;
    }

Ссылка: https://ncalc.codeplex.com/discussions/79258#editor

2
Alien Technology 2 Окт 2014 в 20:43

Вот еще один подход, который я использую:

Я создал метод расширения NCalc, который позволяет обрабатывать параметры и функции на лету.

internal static class NCalcExtensions
{
    public static object Evaluate(this Expression exp, EvaluateParameterHandler evaluateParameters = null, EvaluateFunctionHandler evaluateFunctions = null)
    {
        try
        {
            if (evaluateParameters != null)
                exp.EvaluateParameter += evaluateParameters;

            if (evaluateFunctions != null)
                exp.EvaluateFunction += evaluateFunctions;

            return exp.Evaluate();
        }
        finally
        {
            exp.EvaluateParameter -= evaluateParameters;
            exp.EvaluateFunction -= evaluateFunctions;
        }
    }
}

Помимо прочего, я могу использовать его для запуска фиктивной оценки, чтобы получить имена параметров и функций.

var paramNames = new List<string>();
var functionNames = new List<string>();

expression.Evaluate(
    new EvaluateParameterHandler((s, a) =>
    {
        paramNames.Add(s);
        a.Result = 1; // dummy value
    }),
    new EvaluateFunctionHandler((s, a) =>
    {
        functionNames.Add(s);
        a.Result = 1; // dummy value
    }));
0
Larry 5 Авг 2014 в 15:03