1

我在数据库中有一些列包含HH:MM格式的时间。现在,如果有像11:00 - 12:00then 这样的简单表达式,我可以轻松地在 C# 中创建一个名为 as 的扩展方法,SubtractTime并在运行时传递我的参数。我将我的公式存储在数据库中,例如:

Condition                     Value
ExamTimeRemaing > 10:00       SubtractTime(Original,Remaining)     

现在在上述情况下,我可以SubtractTime在运行时使用反射调用我的函数,但是我的问题是,如果我的表达式变得复杂,例如:

10:00 + 12:00 * 00:02 - 10:11

我如何解析这样的表达式?我不需要编码方面的帮助,因为我已经有了将时间转换为滴答声然后转换为HH:MM. 这更像是一个设计问题。我想要一个可扩展的解决方案,以便我可以有效地创建规则引擎。

4

3 回答 3

0

首先,您必须考虑开发和维护开销。使用 Antlr 等创建表达式解析器是绝对荒谬的,我会使用现成的解决方案,如 Jurassic 等 JavaScript 引擎或任何其他基于 .NET 的简单 JavaScript 引擎。

SQL 存储过程/用户定义函数

此外,如果您的规则存储在数据库本身中,那么您可以使用 SQL 本身的功能来解析和评估表达式,而不是制作解析器。您可以动态组合 SQL 表达式并传递参数。或者创建存储过程或用户定义的函数,这些函数经过充分测试,众所周知且可扩展,并且保留在数据库的上下文中。

开源 .NET JavaScript 引擎

您仍然可以将公式以 JavaScript 格式存储在数据库中,首先 JavaScript 是众所周知的、易于理解的并且能够处理复杂的表达式。有许多免费且稳定的 JavaScript 引擎提供丰富的语言功能,并且您仍然可以在公式中使用现有的 JavaScript 库。例如,将来您需要 Base64,您可以简单地从某个 github 获取 Base64 并将其放入您的 JavaScript。

C# 编译器

CSharpCompilerProvider 类为您提供了一种将 C# 源代码编译成程序集的方法,我要做的是使用一些文本模板创建源文件,在 SQL 中编译和存储程序集以及公式,当我需要调用表达式时,我可以获取编译版本,加载它Assembly.Load并创建具有一些接口的解析类并调用它的方法。.NET 将编译并为您提供程序集,您可以将其存储在数据库中为varbinary(max).

于 2014-02-26T08:04:42.357 回答
0

我会说将其存储为字符串并找到运算符。创建一个递归函数 ParseAndCalc(string input) 以正确的顺序解析和计算结果。像这样的东西:

double ParseAndCalc(string input)
{
    string[] sub;
    double result = 0;
    if(input.Contains("+"))
    {
        sub = input.Split('+');
        foreach(string substring in sub)
        {
            result += ParseAndCalc(substring);
        }
    }
    else if (input.Contains("-"))
    {
        sub = input.Split('-');
        foreach(string substring in sub)
        {
            result -= ParseAndCalc(substring);
        }
    }
    else if (input.Contains("*"))
    {
        sub = input.Split('*');
        foreach(string substring in sub)
        {
            result *= ParseAndCalc(substring);
        }
    }
    else if (input.Contains("/"))
    {
        sub = input.Split('/');
        foreach(string substring in sub)
        {
            double parsed = ParseAndCalc(substring);
            if(parsed != 0)
            {
                result /= ParseAndCalc(substring);
            }
            else
            {
                // Error
            }
        }
    }
    return result;
}
于 2014-02-24T09:43:56.397 回答
0

这里的答案告诉你如何做得足够好。如果你决定尝试这个,我可能会自己选择 ANTLR 路线。

也就是说,我会认真考虑你为什么要这样做。您提到您正在构建一个“规则引擎”。据此,我假设您有一个数据库或其他东西,您希望将一堆业务逻辑存储为“规则”,然后让“规则引擎”读取它并将其应用于某些数据。作为其中的一部分,您希望某种表达式解析器能够解析和评估某些类型的规则。

在查看这样的设计时,我会小心不要混淆解析规则和执行它们的问题。您可以将规则编码为 XML、JSON 或任何您喜欢的内容格式。如果这样做,则根本不必编写解析器。您只需评估表达式。

var myRule = [
  { $value: '10:00' },
  { $add: '12:00' },
  { $multiply: 2 },
  { $subtract: '10:11' }
]
于 2014-02-26T19:11:33.167 回答