Get parameters in an expression using NCalc

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

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 the expression?

According to this post for discussion ( https://ncalc.codeplex.com/discussions/361959 ), but I do not quite understand the answer.

+7
string c # expression ncalc
source share
3 answers

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

The implementation that I tested and works (for your provided sample expression) is to implement the LogicalExpressionVisitor and write its 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.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) { expression.Accept(this); } public override void Visit(ValueExpression expression) { } } 

Then you will use it like:

 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 prints for me "x" and "y".

Pay attention to the use of HashSet in 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 keep a record every time the same variable is used, replace the HashSet with List .


That being said, I have very little experience with NCalc, so my implementation of the redefined LogicalExpressionVisitor methods is a LogicalExpressionVisitor . When I inverted the void Visit(ValueExpression expression) method with expression.Accept(this) , this led to a StackOverflowException . So I just left the implementation empty and seemed to work. Therefore, I would advise you to take my answer here with a very large amount of salt. Your mileage may vary, and I cannot say if this works for all types of expressions.

+12
source share

This works for me. Your mileage may vary.

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

ref: https://ncalc.codeplex.com/discussions/79258#editor

+2
source share

Here is another approach I'm using:

I built the NCalc extension method, which allows you to process parameters and functions on the fly.

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

Among other things, I can use it to run a dummy assessment to get the names of parameters and functions.

 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
source share

All Articles