c# - C#/Python/Ruby 的表达式计算器

标签 c# python ruby expression parser-generator

我们有以下格式的半复杂表达式:
“25 + [变量 1] > [变量 2]”

我们需要一个表达式求值器来解析表达式并使用回调 来请求变量值并计算出表达式的整体结果。它必须是一个回调,因为有成千上万的变量。

我们需要常用的数学运算符,但也需要诸如“if”之类的东西。语言越丰富越好。

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

最佳答案

您是否考虑过使用 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;
        }
    }

关于c# - C#/Python/Ruby 的表达式计算器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4979423/

相关文章:

c# - 控制键的 ListView KeyUp 错误

python - 如何使矩形的副本在屏幕上保持绘制状态并且在pygame中不透水

python - Python 中的元组声明

ruby :未定义的方法 `>'

ruby - 如何将已构建的 Jekyll 站点推送到 GitHub?

c# - 有没有更好的方法来处理转换异常?

c# - Linq 获取表中条目最多的员工的 ID

Python - 类型错误 : 'int' object is not callable

ruby - 将方法从一个类复制到另一个类

c# - 如何统一输入字段的(删除/使不可见/更改颜色)边框?