Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the parameters in an expression using NCalc

I have an expression which I want to parse to get a list of all used parameters.

For example: "X + 5 / (Y - 1)" should give me the following result: X, Y

I already use NCalc in my project; so is it possible to use NCalc to get the parameters used in an expression?

According to this one discussion entry (https://ncalc.codeplex.com/discussions/361959) it is, but I don't quite understand the answer.

like image 639
Preli Avatar asked Apr 11 '14 13:04

Preli


1 Answers

From the discussion/answer here: http://ncalc.codeplex.com/discussions/360990

A implementation that I've tested and works (for your provided sample expression) is to implement a LogicalExpressionVisitor and have it record the parameters as they are found:

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)
    {

    }
}

Then you would use it as:

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);

This outputs "x" and "y" for me.

Note the use of HashSet in the ParameterExtractionVisitor. This is because if your expression contains the same variable more than once (for example: "[x] + [x]") it will be added twice. If you want to store an entry each time the same variable is used, replace the HashSet with a List.


That all said, I have very little experience with NCalc, so my implementation of the overridden methods of LogicalExpressionVisitor are guesses. When I overrode the void Visit(ValueExpression expression) method with expression.Accept(this), it resulted in a StackOverflowException. So I simply left the implementation blank and it seemed to work. So I would suggest that you take my answer here with a very large grain of salt. Your mileage may vary and I can't say if this works for all types of expressions.

like image 143
Chris Sinclair Avatar answered Oct 12 '22 01:10

Chris Sinclair