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

发布于 2024-10-17 09:18:26 字数 228 浏览 2 评论 0原文

我们有半复杂的表达式,格式如下:
"25 + [Variable1] > [Variable2]"

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

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

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

We have semi-complicated expressions in the format:
"25 + [Variable1] > [Variable2]"

We need an expression evaluator to parse the expression and use a callback to ask for the variable values and work out the overall result of the expression. It has to be a callback as there are thousands of variables.

We need the usual math operators but also things like "if" etc. The richer the language the better.

We can use any language we want. Anyone have any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

内心荒芜 2024-10-24 09:18:26

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

Have you considered using Mono.CSharp.Evaluator? It seems like this in conjunction with an appropriatelly set InteractiveBaseClass would do the trick quite nicely, and with minimal effort.

Note that the following uses 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(); } }
    }
}

Real shame it runs a little slow. For instance, on my i7-m620 it takes almost 8 seconds to run this 10,000 times:

[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

It'd be great if we could parse and compile it to IL so we could execute it at .NET speeds, but that sounds like a bit of a pipe dream...

[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

Oh my.

Need excel-like expression constructs like IF? Build your own!

    [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;
        }
    }
不语却知心 2024-10-24 09:18:26

查看 NCalc。它是 .NET,应该支持您的要求。

Check out NCalc. It's .NET and should support your requirements.

愿得七秒忆 2024-10-24 09:18:26

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

请参阅这个 SO 答案,它显示了十几种语言的表达式评估器。您应该能够适应其中一项:

Code Golf:数学表达式求值器(即尊重 PEMDAS)

编辑:无论是谁搞砸了,显然都没有去检查那里的解决方案。是的,有很多是为了满足高尔夫规则(通常是“最小”)而挤在一起的,但其中大多数都用明文版本的算法解释得非常清楚。

Pure expression evaluators are actually pretty easy to write.

See this SO answer which shows expression evaluators in a dozen langauges. You should be able to adapt one of these:

Code Golf: Mathematical expression evaluator (that respects PEMDAS)

EDIT: Whoever dinged this obviously didn't go and examine the solutions there. Yes, there are a bunch that are crammed tight to meet the golf-rules (typically "smallest") but most of them are explained pretty clearly with a cleartext version of algorithm.

猛虎独行 2024-10-24 09:18:26

嗯……你需要一种语言。您有 C#、VB.Net、IronPython、IronRuby 等。

使用正则表达式简单地替换打开的变量(也许您甚至提前知道它们并且只需要一个字符串。替换),然后使用 CodeDOM(对于 C# 或 VB.Net)或使用 DLR(IronPython、IronRuby)编译脚本。您可以简单地将变量作为方法参数添加到用于封装代码(对于 CodeDOM)的方法包装器中,或者只是将变量注入 DLR 中。
我们在业务团队中以更少的努力和可靠的努力实施了这两种变体。

当您紧急需要回调时,请在上面的解决方案中添加一个方法,该方法使用类似 ValueOf(string) 的名称与编程语言的主机进行通信。所以你可以写

ValueOf("A") > ValueOf("B") - 10

玩得开心。

Well ... you need a language. You have C#, VB.Net, IronPython, IronRuby, and others.

Simple replace the open variables using regex (maybe you even know them ahead and just need a string.Replace) and then compile the script using CodeDOM (for C# or VB.Net) or use the DLR (IronPython, IronRuby). You can simply add the variables as method parameters in the method wrapper you use to encapsulate your code (for CodeDOM) or just inject the variables in the DLR.
Both variants we implemented in our team in business with less effort and reliable effort.

When you urgently regquire the callback, well the add to the solutions above a method which communicate with the host of the programming language with a name like ValueOf(string). So you can write

ValueOf("A") > ValueOf("B") - 10

Have fun.

鱼窥荷 2024-10-24 09:18:26

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

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

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

一元运算符 + - !

运算符|| && < <= == != >= > + - * / %

使用 ( ) 分组

如果存在语法错误,则会引发 Expression::SyntaxError。

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

Handles variable lookup via a lambda or block callback.

Understands numeric, string and boolean constants.

Unary operators + - !

Operators || && < <= == != >= > + - * / %

Grouping with ( )

Raises an Expression::SyntaxError if there's a syntax error.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文