C# 动态解析表达式

需求

我们很难捉摸用户的思维,即使使用非常正式的文档规范某些数据的定义、结果的标准等,也不能抵挡住用户不断变化的需求,但他们有个万变不离的东西——你做这个东西要是万能的,即输入参数类型、个数等发生改变,也得生成出正确的结果。

在编程计算中,很多时候涉及一些公式,用户要求不但能够调整系数、还要能够调整理公式的结构。例如,将2+3-5调整理成2+3*5。我之前使用的解决方案是写一个类,换公式了,就继承它,写一个子类,代码中用反射去调用这个子类,可以解决问题。但是有些麻烦。

解决方案

现决定,用动态来解析公式的方法来解决这个问题。由于时间比较紧张,找到了一个开源的类库ExpressionEvaluator,没有深入研究,不过已经解决了我们的问题。

官网:http://csharpeval.codeplex.com/

使用示例

1.在官网下载ExpressionEvaluator. dll(2.0.4版),在网上搜索antlr3.runtime.dll(3.5.0.2版)

2.项目中引用这两个dll;

3.第一种情况,不需要变量,直接是常规的数字、符号、系统函数(Math类)的组合。

/// <summary>
/// 简单数值计算
/// </summary>
/// <param name="str">纯表达式</param>
/// <returns>返回值</returns>
public static string SimpleEval(string str)
{
    var types = new TypeRegistry();
    types.RegisterDefaultTypes();

    var expression = new CompiledExpression(str) { TypeRegistry = types };
    var result = expression.Eval();
    Console.WriteLine("简单数值计算: {0}", result);
    return result.ToString();
}

  

调用:

SimpleEval(this.textBox1.Text.Trim()

  

结果如下:

4.第二种情况,其中包含了一些变量(这种情况更多),需要将自己的变量写成一个类,然后注册这个类。

public class Result
{
    public  double Death { get; set; }
    public  double Injury { get; set; }
}

  

方法:

/// <summary>
/// 变量字段的计算
/// </summary>
/// <param name="str"></param>
/// <param name="type"></param>
/// <returns></returns>
public static string FieldEval(string str,Object type)
{
    //注册
    var reg = new TypeRegistry();
    reg.RegisterSymbol("Result", type);

    //编译
    var p = new CompiledExpression(str) { TypeRegistry = reg };
    p.Compile();

    //计算
    Console.WriteLine("变量字段计算: {0}", p.Eval());
    return p.Eval().ToString();
}

  

调用:

string[] strFields = new string[] { "Death","Injury"};
string exp = this.textBox2.Text.Trim();
for (int i = 0; i < strFields.Length;i++ )
{
    if (exp.Contains(strFields[i]))
    {
        exp= exp.Replace(strFields[i], "Result." + strFields[i]);
    }

}
Result re = new Result()
{
        Death = Convert.ToDouble(this.txtDeath.Text.Trim() + ""),
        Injury = Convert.ToDouble(this.txtInjury.Text.Trim() + "")
};

ExpEvaluator.FieldEval(exp,re)

  

结果:

当然,还有其他内容需要研究、学习!

参考

Github地址:

https://github.com/RupertAvery/csharpeval

调用系统的Math函数:

http://csharpeval.codeplex.com/discussions/585878

时间: 2024-12-23 18:00:13

C# 动态解析表达式的相关文章

报表工具的动态数据源实现

有时候我们需要用参数动态指定数据源,或将多数据源连接为单数据源,或向子报表.table控件动态传入数据源名.对于此类需求,报表工具经常要借助高级语言实现或牺牲安全性以降低复杂度,尤其是BIRT.Jasper等单源报表. 使用免费的集算器可以弥补这一不足.集算器封装了丰富的结构化计算函数,支持动态解析表达式,支持多数据源混合计算,书写简单脚本就能实现动态数据源.集算器还提供了简单易用的JDBC接口,报表工具可将集算器脚本文件当做数据库存储过程执行,传入参数并用JDBC获得返回结果. 集算器与报表工

集算器协助java处理多样性数据源之HDFS

Java通过Hadoop提供的API访问HDFS不算困难,但针对其上文件的计算就比较麻烦.比如分组.过滤.排序等计算,用java来实现都比较复杂.集算器esproc能很好地协助java解决计算问题,同时也封装了HDFS的访问,借助esproc可以让java加强HDFS上文件的计算能力,结构化半结构化数据计算都可以轻松完成.下面我们通过例子来看一下具体作法. HDFS中的文本文件employee.gz中保存了员工数据.我们要读取员工信息,从中找出1981年1月1日(含)之后出生的女员工.文本文件在

集算器协助java处理多样性数据源之JSON

Java的json开源包一般只能解析json数据,没有运算功能.程序员自己写通用的程序来实现分组.排序.过滤.连接这些计算,相当麻烦.例如:用java写json文件条件过滤程序时,当条件表达式发生变化时就需要改写代码.如果要实现象SQL那样灵活的条件过滤,则需要自己实现动态表达式解析和求值,编程工作量非常大. 集算器是支持动态表达式的,可以嵌入到Java中写出通用的json计算程序.下面我们通过例子来看一下具体作法.待处理字符串是json格式的员工信息,包含EID.NAME.SURNAME.GE

集算器协助Java处理结构化文本之分组汇总

直接用Java实现文体文件分组汇总会有如下的麻烦: 1.文件不是数据库,不能用SQL访问.当分组.汇总表达式变化时,只能改写代码.而要实现灵活表达式的话,需要自己实现动态表达式解析和求值,编程工作量非常大. 2.遍历过程中记录分组结果,结果小了还可以存在内存中,如果分组结果太大时要将中间结果缓存进临时文件再归并,实现过程非常复杂. 使用集算器辅助Java编程,这些问题都有现成的类库可以解决.下面,我们通过例子来看一下具体作法. 文本文件employee.txt中保存有员工信息,我们要按照DEPT

集算器协助Java处理结构化文本之条件过滤

直接用Java实现文本文件中数据按条件过滤会有如下的麻烦: 1.文件不是数据库,不能用SQL访问.当过滤条件变化时需要改写代码.如果要实现象SQL那样灵活的条件过滤,则需要自己实现动态表达式解析和求值,编程工作量非常大. 2.文件太大时不能一次性装入内存处理,而采用逐步读入方式在考虑到性能时又会涉及到文件缓冲区管理.拆行计算等复杂编程. 使用集算器来辅助Java编程,这些问题都不需要自己写代码解决.下面我们通过例子来看一下具体作法. 文本文件employee.txt中保存了员工数据.我们要读取员

Java实现文本文件按条件过滤的简便方法

程序开发中经常会碰到处理文本文件中数据的情况,这里通过一个例子来看用java实现文本文件按条件过滤的方法:从文本文件employee.txt中读取员工信息,从中找出1981年1月1日(含)之后出生的女员工. 文本文件empolyee.txt的格式如下: EID   NAME       SURNAME        GENDER  STATE        BIRTHDAY        HIREDATE         DEPT         SALARY 1       Rebecca  

集算器协助java处理多样性数据源之MongoDB

MongoDB不支持join,其官网上推荐的unity jdbc可以把数据取出来进行二次计算实现join运算,但这些join.group.函数.表达式等高级功能都是收费版才有,而且即使是收费版本,对子查询.窗口函数等复杂SQL运算仍不支持.其他免费的jdbc drive就只能支持最基本的SQL语句了. 用免费的esProc配合MongoDB,可以实现上述结构化(半结构化)复杂计算.这里以join为例说明一下具体作法. MongoDB中的文档orders保存了订单数据,employee保存了员工数

Java实现文本文件分组汇总的简便方法

程序开发中经常会碰到处理文本文件中数据的情况,这里通过一个例子来看用java实现文本文件分组汇总的方法:从文本文件employee.txt中读取员工信息,按照DEPT分组,求出每组的员工个数COUNT和薪酬SALARY总额. 文本文件empolyee.txt的格式如下: EID   NAME       SURNAME        GENDER  STATE        BIRTHDAY        HIREDATE         DEPT         SALARY 1      

Java读写Excel文件中数据的简便方法

Java开发项目中经常会碰到处理Excel文件中数据的情况,这里通过一个例子来看一下实现方法:从Excel文件orders.xls中读取订单信息,从中找出2010年1月1日(含)之后,并且SELLERID等于18的订单.找到的数据写入order_result.xls文件. Excel文件orders.xls的内容如下: ORDERID CLIENT SELLERID AMOUNT ORDERDATE 1 UJRNP 17 392 2008/11/2 15:28 2 SJCH 6 4802 200