C#/ Python / Ruby的表达式求值程序

时间:2011-02-12 17:20:51

标签: c# python ruby expression parser-generator

我们有半复杂的表达格式:
“25 + [Variable1]> [Variable2]”

我们需要一个表达式求值程序来解析表达式并使用回调来询问变量值并计算出表达式的整体结果。它必须是回调,因为有数千个变量。

我们需要通常的数学运算符,但也需要“if”等等。语言越丰富越好。

我们可以使用我们想要的任何语言。有人有什么建议吗?

5 个答案:

答案 0 :(得分:3)

你考虑过使用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<double> Variable1Callback;

        public static Double Variable1 { get { return Variable1Callback(); } }

        internal static Func<double> 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<T>(bool expr, T trueValue, T falseValue)
        {
            return expr ? trueValue : falseValue;
        }
    }

答案 1 :(得分:2)

结帐NCalc。它是.NET,应该支持您的要求。

答案 2 :(得分:1)

纯表达式求值器实际上很容易编写。

请参阅此SO答案,其中显示了十几个语言中的表达评估者。你应该能够适应其中一个:

Code Golf: Mathematical expression evaluator (that respects PEMDAS)

编辑:没有人这样做,显然没有去检查那里的解决方案。是的,有一堆紧紧地挤满了高尔夫球规则(通常是“最小的”)但是大部分都用明文版的算法清楚地解释了。

答案 3 :(得分:0)

嗯......你需要一门语言。你有C#,VB.Net,IronPython,IronRuby等。

使用正则表达式简单替换open变量(可能你甚至知道它们只需要一个string.Replace)然后使用CodeDOM(对于C#或VB.Net)编译脚本或使用DLR(IronPython,IronRuby)。您可以简单地将变量作为方法参数添加到用于封装代码的方法包装器中(对于CodeDOM),或者只是在DLR中注入变量。 我们的团队在业务中实施了这两种变体,省力省力。

当您急需查询回调时,请添加上述解决方案,该方法与编程语言的主机通信,其名称为ValueOf(string)。所以你可以写

ValueOf(“A”)&gt; ValueOf(“B”) - 10

玩得开心。

答案 4 :(得分:0)

http://code.google.com/p/bc-expression/

通过lambda或块回调处理变量查找。

理解数字,字符串和布尔常量。

一元运算符+ - !

运营商|| &安培;&安培; &LT; &lt; = ==!=&gt; =&gt; + - * /%

使用()

进行分组

如果出现语法错误,则引发Expression :: SyntaxError。