C#/ Python / Ruby的表达式求值程序
我们在格式中有半复杂的表达式:
“25 + [Variable1]> [Variable2]”
我们需要一个表达式求值程序来解析表达式并使用回调来请求变量值并计算出表达式的整体结果。 它必须是一个回调,因为有数千个变量。
我们需要通常的数学运算符,但也需要“if”等等。语言越丰富越好。
我们可以使用我们想要的任何语言。 有人有什么建议吗?
看看NCalc 。 它是.NET,应该支持您的要求。
你考虑过使用Mono.CSharp.Evaluator吗? 看起来这与适当设置的InteractiveBaseClass相结合可以很好地完成这个技巧,并且只需要很少的努力。
请注意,以下使用Mono 2.11.1 alpha。
using System; using System.Diagnostics; using Mono.CSharp; using NUnit.Framework; public class MonoExpressionEvaluator { [Test] public void ProofOfConcept() { Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter())); evaluator.InteractiveBaseClass = typeof (Variables); Variables.Variable1Callback = () => 5.1; Variables.Variable2Callback = () => 30; var result = evaluator.Evaluate("25 + Variable1 > Variable2"); Assert.AreEqual(25 + Variables.Variable1 > Variables.Variable2, result); Console.WriteLine(result); } public class Variables { internal static Func Variable1Callback; public static Double Variable1 { get { return Variable1Callback(); } } internal static Func Variable2Callback; public static Double Variable2 { get { return Variable2Callback(); } } } }
真正的耻辱它运行有点慢。 例如,在我的i7-m620上运行10,000次需要大约8秒钟:
[Test] public void BenchmarkEvaluate() { Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter())); evaluator.InteractiveBaseClass = typeof(Variables); Variables.Variable1Callback = () => 5.1; Variables.Variable2Callback = () => 30; var sw = Stopwatch.StartNew(); for (int i = 1; i < 10000; i++) evaluator.Evaluate("25 + Variable1 > Variable2"); sw.Stop(); Console.WriteLine(sw.Elapsed); }
00:00:07.6035024
如果我们可以将它解析并编译为IL,那么我们可以以.NET的速度执行它,这很好,但这听起来像是一个梦想……
[Test] public void BenchmarkCompiledMethod() { Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter())); evaluator.InteractiveBaseClass = typeof(Variables); Variables.Variable1Callback = () => 5.1; Variables.Variable2Callback = () => 30; var method = evaluator.Compile("25 + Variable1 > Variable2"); object result = null; method(ref result); Assert.AreEqual(25 + Variables.Variable1 > Variables.Variable2, result); Variables.Variable2Callback = () => 31; method(ref result); Assert.AreEqual(25 + Variables.Variable1 > Variables.Variable2, result); var sw = Stopwatch.StartNew(); for (int i = 1; i < 10000; i++) method(ref result); sw.Stop(); Console.WriteLine(sw.Elapsed); }
00:00:00.0003799
天啊。
需要像IF这样的类似excel的表达式构造吗? 建立你自己的!
[Test] public void ProofOfConcept2() { Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter())); evaluator.InteractiveBaseClass = typeof(Variables2); Variables.Variable1Callback = () => 5.1; Variables.Variable2Callback = () => 30; var result = evaluator.Evaluate(@"IF(25 + Variable1 > Variable2, ""TRUE"", ""FALSE"")"); Assert.AreEqual("TRUE", result); Console.WriteLine(result); } public class Variables2 : Variables { public static T IF(bool expr, T trueValue, T falseValue) { return expr ? trueValue : falseValue; } }
纯表达式评估器实际上很容易编写。
看到这个SO答案,它显示了十几个语言中的表达评估者。 你应该能够适应其中一个:
Code Golf:数学表达式评估器(尊重PEMDAS)
编辑:谁明白这个,显然没有去检查那里的解决方案。 是的,有一堆紧紧地塞满了高尔夫规则(通常是“最小的”),但大多数都用明文版的算法清楚地解释了。
嗯……你需要一门语言。 你有C#,VB.Net,IronPython,IronRuby等。
使用正则表达式简单替换open变量(可能你甚至知道它们只需要一个string.Replace)然后使用CodeDOM(对于C#或VB.Net)编译脚本或使用DLR(IronPython,IronRuby)。 您可以简单地将变量作为方法参数添加到用于封装代码的方法包装器中(对于CodeDOM),或者只是在DLR中注入变量。 我们在团队中实施的这两种变体都付出了较少的努力和可靠的努力。
当您急需查询回调时,请在上面的解决方案中添加一个方法,该方法与编程语言的主机通信,其名称为ValueOf(string)。 所以你可以写
ValueOf(“A”)> ValueOf(“B”) – 10
玩得开心。
http://code.google.com/p/bc-expression/
通过lambda或块回调处理变量查找。
理解数字,字符串和布尔常量。
一元运算符+ – !
运营商|| && << = ==!=> => + – * /%
用()分组
如果存在语法错误,则引发Expression :: SyntaxError。