Параметры в выражении через NCalc
У меня есть выражение, которое я хочу разобрать, чтобы получить список всех используемых параметров.
например: "X + 5 / (Y-1)" должен дать мне следующий результат: X, Y
Я уже использую NCalc в своем проекте; так можно ли использовать NCalc для получения параметров, используемых в выражении?
согласно этой одной записи обсуждения (https://ncalc.codeplex.com/discussions/361959) это так, но я не совсем понимаю ответ.
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.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)
{
}
}
тогда вы бы использовали его как:
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
are предположения. Когда я переехал void Visit(ValueExpression expression)
метод expression.Accept(this)
, в результате StackOverflowException
. Поэтому я просто оставил реализацию пробел и казалось на работу. Поэтому я предлагаю вам принять мой ответ здесь с очень большие зерном соли. Ваш пробег может отличаться, и я не могу сказать, работает ли это для всех типов выражений.
это работает для меня. Ваш пробег может отличаться.
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;
}
вот еще один подход, который я использую:
Я построил метод расширения 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
}));