【问题标题】:What is the simplest way to parse an expression and retrieve a parse tree?解析表达式和检索解析树的最简单方法是什么?
【发布时间】:2012-06-08 10:47:01
【问题描述】:

我只想解析简单的表达式,比如 -

IIF(FVAL(PFC) = TRUE, (IIF((ORGVAL(BAS, "2012/12/31") + ORGVAL(DA)) < 6500, (FVAL(BAS)  + FVAL(DA)) * 12%, 780)), 0)`

解析后应该可以知道哪些函数包含哪些参数。

|-FVAL
       |-PFC
|-ORGVAL 
       |-BAS
       |-"2012/12/31"

我被 .Net Framework 2.0 困住了,所以我没有 Linq 或 lambda 表达式的好东西。此外,我想将代码包含在我的自定义库中,而不仅仅是引用它。谁能指点我一些好的库或代码。

我只需要解析而不是评估表达式并找出正在使用的标记。找到标记后,我需要在解析之前更改表达式字符串,例如如果使用函数ORGVAL,则传递的参数必须带有下划线前缀。就像ORGVAL(BAS) 将转换为ORGVAL(_BAS)。有些函数可以有两个参数,比如ORGVAL(BAS, "2012/12/31"),这将转换为ORGVAL(_BAS, "2012/12/31")

注意:如果有其他方法,请告诉我。我希望避免使用解析器和词法分析器。

【问题讨论】:

  • ANTLR。或者另一个语法解析器..
  • @Yossarian ANTLR 对我来说太难了。我对此一无所知。也许更简单一些。
  • 忽略通用解决方案使其成为购物问题的标志。在所有 SE 网站上偏离主题。

标签: c# vb.net parsing .net-2.0 expression-trees


【解决方案1】:

如果您不介意使用其中一种 .NET 语言编写代码,您可以使用 CodeDom 即时编译代码,然后将其作为仅内存程序集执行。例如,这将是您展示的示例表达式最接近的近似值:

private abstract class Logic
{
    protected double FVAL(object arg)
    {
        // put code here
        return 0;
    }

    protected double ORGVAL(object arg)
    {
        // put code here
        return 0;
    }

    protected double ORGVAL(object arg, string date)
    {
        // put code here
        return 0;
    }

    public abstract double GetValue(object PFC, object BAS, object DA);
}

private class DynamicLogic : Logic
{
    public override double GetValue(object PFC, object BAS, object DA)
    {
        return (FVAL(PFC) = true ? ((ORGVAL(BAS, "2012/12/31") + ORGVAL(DA)) < 6500 ? (FVAL(BAS) + FVAL(DA)) * .12 : 780) : 0);
    }
}


private Logic GenerateLogic(string code)
{
    using (CSharpCodeProvider provider = new CSharpCodeProvider())
    {
        StringBuilder classCode = new StringBuilder();
        classCode.AppendLine("private class DynamicLogic : Logic");
        classCode.AppendLine("    {");
        classCode.AppendLine("        public override int GetValue(object PFC, object BAS, object DA)");
        classCode.AppendLine("        {");
        classCode.AppendLine("            return (" + code + ");");
        classCode.AppendLine("        }");
        classCode.AppendLine("    }");
        CompilerParameters p = new CompilerParameters();
        p.GenerateInMemory = true;
        p.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
        CompilerResults results = provider.CompileAssemblyFromSource(p, code);
        return (Logic)Activator.CreateInstance(type);
        if (results.Errors.HasErrors)
        {
            throw new Exception("Failed to compile DynamicLogic class");
        }
        return (Logic)results.CompiledAssembly.CreateInstance("DynamicLogic");
    }
}

private double evaluate(object PFC, object BAS, object DA)
{
    Logic logic = GenerateLogic("FVAL(PFC) = true ? ((ORGVAL(BAS, \"2012/12/31\") + ORGVAL(DA)) < 6500 ? (FVAL(BAS) + FVAL(DA)) * .12  : 780) : 0");
    return logic.GetValue(PFC, BAS, DA);
}

编辑:我知道你说过你需要真正得到表达式三本身,而不仅仅是评估它,而是我处理了代码,所以我想我还是继续发布留给未来的路人。

【讨论】:

  • 我们试过这个方法,速度极慢。我们已经改用Flee。这要快得多。但是对于一些仍在进行的糟糕的技术设计,我需要根据一些逻辑来改变表达方式。无论如何,我想做的就是用_BAS替换BAS
【解决方案2】:

这看起来像是一个未经修饰但完整的表达式解析器(尚未对其进行测试,但可能是一个起点)。

http://gbacon.blogspot.it/2005/09/simple-expression-parser-in-c.html

它很旧,但您提到了 C# 2.0,所以无论如何它可能没问题。我不确定它针对的是哪个版本的 C#。

【讨论】:

    【解决方案3】:

    您想做的事情听起来很像解析,所以我认为您不会很幸运地找到不涉及解析的解决方案。如果您想说的是您不想自己编写解析器,那么有几个可用的数学表达式解析库。

    我是 Jep.Net (http://www.singularsys.com/jep.net) 的作者之一,它是一个可能满足您需求的表达式解析组件。它有据可查,高度可定制,肯定会让您跳过实现自己的自定义解析器的繁琐且容易出错的过程。如果它不适合您,谷歌搜索“.net 表达式解析库”将为您提供其他库。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 2011-03-03
      • 2014-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-21
      • 2014-05-07
      • 2011-02-08
      • 2012-07-28
      相关资源
      最近更新 更多