表达式解析引擎的设计

原创 2011年01月09日 23:40:00

前言

表达式的计算是一个一般性的问题。在报表领域,经常会出现支持计算公式的需求。MS Office Excel中的函数计算就是一个很好的参考例子。

本文提供一个表达式引擎的设计方案,能够满足报表领域的复杂计算要求。

 

一个良好的表达式引擎应该支持基本的二元运算和函数调用,而且二元运算能够嵌套函数调用,函数调用也能够嵌套二元运算,比如:

例子1:=2>1&&((Num(1)+2*Num((Num(2)+2)*3/Num(2)))/2>0||2>1)&&0>1,执行结果:0

例子2:=Switch(Num(1),是, Num(0),否),执行结果:是

例子3:=Switch(20<10,1 ,20>=10, 20 + 20*0.1),执行结果:22

 

当然,实际的应用里,表达式中要支持变量的绑定,比如:

例子1(计算税后金额):=Fields!数量.Value * Fields!单价.Value*(1 + Fields!税率.Value / 100)

例子2(不同价格不同税后金额):=Fields!数量.Value*Fields!单价.Value*Switch(Fields!单价.Value<100, 1.1, Fields!单价.Value<500, 1.08, Fields!单价.Value<800, 1.07)

 

至于常用的一元运算,能够通过函数调用就很方便的实现,例如:取非,Not(exp1)。

 

表达式的定义

要支持二元运算能够嵌套函数调用,函数调用也能够嵌套二元运算,需要采用解析器设计模式,定义数个表达式对象,用表达式对象树来描述表达式字符串。

值表达式:用来描述一个常量或变量,例如:1.1,Fields!数量.Value,Parameters!经手人.Value,字符串

二元表达式:用来描述一个二元运算,例如:exp1 + exp2,exp1

函数表达式:用来描述一个函数调用,例如:Num(exp1),Sum(exp1), Switch(cond1, proc1, cond2, proc2…)

 

运算符优先级

运算符优先级很重要,决定了运算的顺序,特别是括号,能够改变表达式的运算顺序。

优先级

运算符

说明

-1

(

左括号

-1

)

右括号

-2

^

幂运算

-3

*

-3

/

-3

%

取余

-4

+

-4

-

-5

<

小于

-5

<=

小于等于

-5

>

大于

-5

>=

大于等于

-6

==

等于

-6

!=

不等于

-7

&&

逻辑与

-8

||

逻辑或

 

表达式引擎的工作流程

 

二元运算解析生成后缀表达式数组的过程

中缀表达式解析成后缀表达式的方法如下,要借用一个临时堆栈stack,输出是后缀表达式数组output:

(1)从右向左依次读取表达式字符串str。

(2)如果str是操作数(常量或变量),输出到output。

(3)如果str是运算符(含左右括号),则做以下判断:

    a) 如果str = '(',放入堆栈stack。

    b)如果str = ')',依次弹出堆栈stack中的运算符输出到output,直到遇到'('为止。

    c)如果str不是')'或者'(',那么就和堆栈stack顶点位置的运算符top做优先级比较。

      1)如果top是'('或者str优先级比top高,那么将str放入堆栈stack。

      2)如果str优先级低于或者等于top,那么输出top到output,然后将str放入堆栈stack。

(4)如果表达式字符串已经读取完成,而堆栈stack中还有运算符时,依次由顶端输出到output。

 

后缀表达式数组生成表达式对象树的过程

计算后缀表达式的方法如下,要借用一个临时堆栈stack:

(1)从左向右扫描后缀表达式数组,依次取出一个数组元素data。

(2)如果data是表达式,就压入堆栈stack。

(3)如果data是运算符,就从堆栈stack中弹出此运算符需要用到的表达式的个数(二元运算符需要2个),创建一个新二元表达式,然后把二元表达式压入堆栈stack。

(4)如果数组处理完毕,堆栈stack中最后剩余的表达式就是最终结果。

 

例如,表达式=(Num(1)+2*Num(Num(2)+2*3/Num(2)))/2,生成的后缀表达式数组如下:

0:    Method{num, [Const(1)]}

1:    Const(2)

2:    Method{num, [Binary{+, Method{num, [Const(2)]}, Binary{/, Binary{*, Const(2), Const(3)}, Method{num, [Const(2)]}}}]}

3:    *

4:    +

5:    Const(2)

6:    /

该后缀表达式数组生成的表达式对象树如下:

Binary{/, Binary{+, Method{num, [Const(1)]}, Binary{*, Const(2), Method{num, [Binary{+, Method{num, [Const(2)]}, Binary{/, Binary{*, Const(2), Const(3)}, Method{num, [Const(2)]}}}]}}}, Const(2)}

 

剩下的工作就是执行表达式对象树,输出结果。

表达式引擎aviator

表达式引擎aviator

Fel轻量高效的表达式计算引擎

Fel是轻量级的高效的表达式计算引擎 Fel在源自于企业项目,设计目标是为了满足不断变化的功能需求和性能需求。 Fel是开放的,引擎执行中的多个模块都可以扩展或替换。Fel的执行主要是通过函数实现...

最简单却又极具扩展性的Java表达式引擎,自创编程语言必备

这个表达式引擎只有短短的100多行,却能实现包括加减乘除、括号优先级在内的运算,可以在“处理表达式”函数中自行扩展想要处理的算法。这里面算法的难点主要在于如何实现在多级括号存在的情况下,能取出最外层的...
  • yry0304
  • yry0304
  • 2016年12月05日 10:32
  • 1937

Java 解析表达式

最近项目需要用到配置表达式,然后后台解析表达式并运行得到结果,类似这种"true||true"表达式,java里自带的不支持这种,只能用java里的ScriptEngine的js引擎来执行,但是效率太...

自己实现一个SQL解析引擎 功能:将用户输入的SQL语句序列转换为一个可执行的操作序列,并返回查询的结果集。 SQL的解析引擎包括查询编译与查询优化和查询的运行,主要包括3个步骤: 查询分析

自己实现一个SQL解析引擎 功能:将用户输入的SQL语句序列转换为一个可执行的操作序列,并返回查询的结果集。 SQL的解析引擎包括查询编译与查询优化和查询的运行,主要包括3个步骤: 查...
  • hanfazy
  • hanfazy
  • 2017年09月18日 13:22
  • 265

Aviator 表达式求值引擎开源框架

简介¶Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢? Aviator...
  • lxzo123
  • lxzo123
  • 2010年12月17日 15:22
  • 9825

java 表达式解析框架

KExpressionV2.0简易表达式解析器使用说明 目录 1. IK表达式介绍(IK Expression Introduction)2. 快速入门(Quick Start)3. ...

利用堆栈解析算术表达式

1本文目标 分析用堆栈解析算术表达式的基本方法。给出的示例代码能解析任何包括+,-,*,/,()和0到9数字组成的算术表达式。 2中缀表达式和后缀表达式 中缀表达式就是通常所说的算术...

表达式解析器 IKExpression

IK Expression 开源,可扩展基于java的表达式解析器。并且不依赖与其他jar,仅作为单独的jar提供功能。 使用场景: 场景1:当接受到字符串 "(a > 2 || b 2"时,作...

Jexl解析表达式

例1: public static void main(String[] args) { Map params =new HashMap(); params.put("id", ...
  • shang02
  • shang02
  • 2016年10月28日 16:53
  • 1609
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:表达式解析引擎的设计
举报原因:
原因补充:

(最多只允许输入30个字)