我有一个表达式,我想解析它以获取所有使用参数的列表。
例如:“X + 5 / (Y - 1)”应该给我以下结果:X,Y
我已经在我的项目中使用了 NCalc;那么是否可以使用 NCalc 来获取表达式中使用的参数?
根据这个讨论条目(https://ncalc.codeplex.com/discussions/361959)它是,但我不太明白答案。
我有一个表达式,我想解析它以获取所有使用参数的列表。
例如:“X + 5 / (Y - 1)”应该给我以下结果:X,Y
我已经在我的项目中使用了 NCalc;那么是否可以使用 NCalc 来获取表达式中使用的参数?
根据这个讨论条目(https://ncalc.codeplex.com/discussions/361959)它是,但我不太明白答案。
从这里的讨论/答案:http: //ncalc.codeplex.com/discussions/360990
我测试并工作的一个实现(对于您提供的示例表达式)是实现 aLogicalExpressionVisitor
并让它记录找到的参数:
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
. 所以我只是将实现留空,它似乎工作。所以我建议你在这里用大量的盐来回答我的问题。您的里程可能会有所不同,我不能说这是否适用于所有类型的表达式。
这对我有用。你的旅费可能会改变。
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
}));