论坛首页 编程语言技术论坛

Spads 公式解析系统 - Java

浏览 5346 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-11-03  

很多网络应用中,涉及到一些内部运算的具体求值逻辑并不能够在开发阶段就定下来。这些逻辑需要随着使用,探测用户反应,不断修正。符合的情况,常见的就是网络游戏中的行动收获计算公式,等等。现 Spads 开发组推出了针对此种情况的解析公式系统,供大家使用。

此公式解析系统能够计算各种算术运算、逻辑运算和比较运算,可以连接本地函数,支持括号分级,允许逐级设置公式内临时变量,提供了分支运算符,并且支持 Json 数据格式的运算。系统编写中使用了很多设计方法,包括概念抽取、继承、多态、面向接口设计、枚举、递归、工厂等等。数据结构也使用了好用但少见的双端队列。很适合对应情况的实用以及学习 Java 的设计思路、编程方式。本程序由 Shane Loo LI 设计和编写,所有的细节都注重了运行效率,在很多细节上都制作了数倍优于爪哇(Java)系统类库的方法;由于只需要处理公式,所以语法树结构单一,也因此保证了比现有其它注入语言的代码解释器更高的执行速度。

下面来介绍一下公式解析系统的用法。
首先,公式通过 ?= 来给变量赋值。这种赋值并不是一个运算,而是公式每一行需要且只能出现一次的专属符号。
Result ?= 38 * 6
公式解析系统用 Result 来表示最终的结果。以上公式表示最终的结果为 228 。

本系统支持以下算术运算:
求负 -
加 +
减 -
乘 *
除 /
求余 %
乘方 ^
阶乘 !
比如

Result ?= ((2^5 - (-13)) % 10)!

能够得到 120 。

接下来,让我们看看公式系统的分支控制。

DayCount ?= 31
DayCost ?= 58.5
Limit ?= 1500
Result ?= DayCount * DayCost > Limit ? "超支了!" ~ "没超支"

我们看到整个公式分为四行。每行声明了一个变量。
实际上在这个公式系统中,并不严格要求上边的公式不能够使用下边公式声明的变量,但如果嵌套使用则会抛出异常。
上述公式将得到一个字符串,内容是“超支了”。

支持的有关运算如下:
大于 >
小于 <
等于 =
与 &
或 |
非 -(这个和 C 语言系列的 ! 有所不同)
条件 ?
分支 ~(这个和 C 语言系列的 : 有所不同)

这个系统最重要的特性,就是能够把公式中出现的函数,和本地函数绑定起来。
只需要制作 Function 接口的实现类,并且在 FunctionEnum 对其进行注册,就能够得到一种可以在公式中识别的函数。
我最近学习了“约定优于明示”的思想,近期会将这种 FunctionEnum 配置方式进行一定程度的更改。

比如,我提供了内置函数 TOGETHER ,其含义是以第一个参数为名称,第二个参数为值,构成键值对;第三个参数为名称,第四个参数为值,构成键值对;等等。最终将其组合成 Json 字符串。请看如下公式。

Name ?= "Shane"
Level ?= 16
Result ?= TOGETHER(\"name\", Name, "graduated", Level > 10 ? "毕业了" ~ "没毕业")

最终结果为 {"name": "Shane", "graduated": "毕业了"}


说了这么多公式解析系统的用法。现在来从编程角度介绍一下如何启用此系统功能。
首先,肯定是要导入 .jar 包。然后参看以下代码。

EvaluatorFactory factory = EvaluatorFactory.INST;
Evaluator eva = factory.getEvaluator("Result ?= 28 + 2 / 10.0");
ExpValue result = eva.evaluate();
System.out.println(result);

或者

String form = "Result ?= 28 + 2 / 10.0";
ExpValue result = EvaluatorFactory.INST.getEvaluator(form).evaluate();

首先,计算器工厂是单例的,但以后如果要扩展函数库,则可以改写成多种工厂。获取工厂后,传入公式字符串(多行),以通过工厂获取针对此公式的计算器。然后调用计算器的计算方法,即可获得公式最终的结果。

如有疑问,可以联系 Surmounting@gmail.com
项目包下载地址为: http://download.csdn.net/detail/shanelooli/4726670

本文也在我的 CSDN 日志中发表: http://blog.csdn.net/shanelooli/article/details/8142726

   发表时间:2012-11-05  
不知道效率如何?
0 请登录后投票
   发表时间:2012-11-05  
这个类似于现行的很多解析引擎,spel、bsh。国人能自己搞一个,表示支持,但能否给出相关的测试效果和执行效率方面的测试数据。
0 请登录后投票
   发表时间:2012-11-05   最后修改:2012-11-05
看着类似Rhino脚本引擎,JEXL表达式引擎,还有温少的fastEL

不知道楼主这个并发性能如何,支不支持jsr223
0 请登录后投票
   发表时间:2012-11-06  
国外开发的spel和beanshell确实好用,不过偶尔也有不符合我们国情的地方,现在做系统有很多大型业务报表和统计数据有些公式有嵌套或引用,有些财务报表甚至有递归,期待国产超级公式,可以代数,可以自解方程,可以使用数学符号求导求积分。
0 请登录后投票
   发表时间:2012-11-06  
h248980496 写道
国外开发的spel和beanshell确实好用,不过偶尔也有不符合我们国情的地方,现在做系统有很多大型业务报表和统计数据有些公式有嵌套或引用,有些财务报表甚至有递归,期待国产超级公式,可以代数,可以自解方程,可以使用数学符号求导求积分。

估计这个压力太大了。。。
0 请登录后投票
   发表时间:2012-11-06  
h248980496 写道
国外开发的spel和beanshell确实好用,不过偶尔也有不符合我们国情的地方,现在做系统有很多大型业务报表和统计数据有些公式有嵌套或引用,有些财务报表甚至有递归,期待国产超级公式,可以代数,可以自解方程,可以使用数学符号求导求积分。


求定积分的话,其实是比较很好做的。但是化简积分式是比较难做的。至少我现在想了想,觉得完全无思路。
求导得走文本识别,能做。

现在的问题是定积分是求值,其它的那些带来的都是某函数式本身的改变,是对运算方式的运算,而不是对数值的运算。
这二者是不同的。那么,做什么是更有意义的?定下来,那么我下次有机会可以做一做。

对了,给自己拉个票: http://blog.51cto.com/contest2012/5523233
0 请登录后投票
   发表时间:2012-11-06  
我觉得javaeye论坛最好的地方就是主贴里面的相关文章 ,比如 对比下IKExpression 就可以看到很多东西。
0 请登录后投票
   发表时间:2012-11-07  
char1st 写道
我觉得javaeye论坛最好的地方就是主贴里面的相关文章 ,比如 对比下IKExpression 就可以看到很多东西。


IK Expression 那篇文写得实在太好了。看来我也得找个时间好好写写文。IK Expression 能做的我这边都能做哦。

接下来,说说我这边的优势:
1、所有的函数都不用指定参数类型,直接用。
2、去除了不需要用的操作符,简化了操作符语法
3、★ 支持 Json 运算。
4、配置使用了理念更先进的 枚举 配置,之后准备改用类路径扫描 + 标注配置。
5、内置函数比 IK Expression 简洁且功能强大。比如各情况按概率出现的函数,以及结合成 Json 的函数等。
6、摆脱了标准编译器的执行步骤,分离为简洁的“识别”、“运算”二步。

受到的启发:
甲、我忘了做字符串相加和 Json 相加了……这个需要做一下的。
乙、需要找时间做一下并发性能和顺序性能测试,以便证其优势~
0 请登录后投票
   发表时间:2012-11-22  
pangyi 写道
不知道效率如何?

我最近终于有人力组织这边的性能测试啦!
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics