为什么需要 EL 表达式引擎
绝大多数人的绝大多数项目,是不需要一个嵌入式的表达式引擎的。因此,提供这个功能的目的就是:
满足一小撮人的一小撮要求
但是,"一小撮人"的"一小撮要求"有很多,作为一个小众类库,为什么单单打算支持这个特性呢?下面是我的理由:
- 这个功能是其它模块功能的基础,我们需要它
-
可能因此吸引其他的开发者对 Nutz 的兴趣
-
需要嵌入式表达式引擎的人是 Java 开发者的少数人,但是这些人也应该比 Nutz 的用户要多
- 这些人基本上编程水平要强一些
- 其他的提交者对增加这个特性没有特别强烈的反对
近一步介绍表达式引擎
那么它怎么使用呢?
是的,我想这可能会是你脑海里闪出的第一个问题。并且,我想你真正想问的是:“它好用吗?”
如果你脑海里第一个问题不是这个,而是:“表达式引擎是神马东东?” 那么建议你不用阅读本文了,反正你也用不着。等你需要的时候,再读也不迟,反正这篇文章又不长。
而关于 "好用",还有下面这三层含义:
它容易使用吗?
System.out.println(El.eval("3+4*5").equals(23)); // 将打印 true,够简单吧
表达式接受的是字符串输入,输出则是一个Object对象,而Object对象本身是根据计算结果进行进行了自动封装的。
它功能强大吗?
虽然在 #一些表达式的例子 这一节我有更详细的例子,但是这里我必须要先概括几点:
它支持变量,比如
Context context = Lang.context();
context.set("a", 10);
System.out.println(El.eval(context, "a*10")); // 将打印 100
通过 Context 接口,你可以为你的表达式随意设置变量的值。它支持如下类型的 Java 数据
- 整型 - int 或 Integer
- 浮点 - float 或 Float
- 长整 - long 或 Long
- 布尔 - boolean 或 Boolean
- 字符串 - String
- 数组 - T[]
- 列表 - Lst<Ti>
- 集合 - Collection<T>
- Map - Map<String,?>
- 普通 Java 对象
基本上,有了这些,你可以为所欲为了吧。
它速度怎么样?
我觉得它速度不怎么样。它的工作的原理是这样的,每次解析都经过如果下三步
- 解析成后缀表达式形式的一个队列
- 将后缀表达式解析成一棵运算树.
- 对运算树的根结点进行运算.
当然我也提供了一个提升效率的手段,因为如果每次计算都经过这三个步骤当然慢,所以我们可以对它先预编译:
El exp = new El("a*10"); // 预编译结果为一个 El 对象
Context context = Lang.context();
context.set("a", 10);
System.out.println(exp.eval(context)); // 将打印 100
El在实例化时就会对表达式进行预编译,会直接编译成运算树,当调用eval方法时,就不用再耗时的编译动作了.
它的 eval 函数是线程安全的,只要在多个线程内给它不同的 context 就是了。当然,你也可以在多个线程间共享同一个 Context,那运行起来一定很有趣,不是吗?
支持什么样的操作符
我想但凡有机会和兴趣读到这篇文字的同学,一定是编程老手,即使是自称小白的的同学们,你们对一个编程语言应该支持的操作符基本都差不多熟的不行,所以,我就不在这里唠叨操作符的具体细节了,我只给一个列表,告诉你我现在支持什么操作符。
另外,再加上一句:
只要支持的操作符,我会让它的优先级以及行为会和 Java 的表达式一致。如果你发现不一致别犹豫,给我报 Issue 吧。
符号 |
权重 |
解释 |
() |
100 |
括号,优先计算 |
, |
0 |
逗号,主要是方法参数 |
. |
1 |
访问对象的属性,或者Map的值,或者方法调用,或者自定义函数调用(需要结合后面是否有括号)
|
['abc'] |
1 |
Java 对象 Map按键值获得值 |
[3] |
1 |
数字,列表,或者集合的下标访问符号 |
* |
3 |
乘 |
/ |
3 |
整除 |
% |
3 |
取模 |
+ |
4 |
加 |
- |
4 |
减 |
- |
2 |
负 |
>= |
6 |
大于等于 |
<= |
5 |
小于等于 |
== |
7 |
等于 |
!= |
6 |
不等于 |
! |
7 |
非 |
> |
6 |
大于 |
< |
6 |
小于 |
&& |
11 |
逻辑与 |
| | |
12 |
逻辑或 |
?: |
13 |
三元运算 |
& |
8 |
位运算,与 |
~ |
2 |
位运算,非 |
| |
10 |
位运算,或 |
^ |
9 |
位运算,异或 |
<< |
5 |
位运算,左移 |
>> |
5 |
位运算,右移 |
>>> |
5 |
位运算,无符号右移 |
& |
8 |
位运算,与 |
当然,同任何编程语言一样,表达式也支持 左括号
( 以及 右括号),来控制表达式的的计算优先级别
自定义函数
好吧, 你肯定要说上面的功能简直弱爆了, 就一点简单的加加减减有什么好稀奇的, 再强点的需求就没办法满足了.确实是这样, 所以, 我们在 EL 里面添加了自定义函数, 嘿嘿, 这回强了吧. 言归正传,下面详细的说说它的使用, 以及怎么自定义.
现有的自定义函数:
名称 |
参数 |
解释 |
例子 |
max |
任意个Number型 |
取出参数中最大值 |
max(1, 2, 3, 4)=>4 |
min |
任意个Number型 |
取出参数中最小值 |
min(1, 2, 3, 4)=>1 |
trim |
一个String |
去掉字符串两边的空格 |
trim(" 1 ")=> "1" |
使用很简单吧.
当EL里面的功能无法满足你的需求时, 你可以自定义一些功能来实现, 怎么自定义呢?
# 创建一个类, 使它实现 org.nutz.el.opt.RunMethod, org.nutz.plugin.Plugin 这两个接口.
# 在配置文件中添加一个配置项:
{
"EL": {"custom":[...函数列表...]}
}
# 如果你只使用了EL这一个模块, 没有其它模块, 并且在其它地方都没有加载过配置, 请使用下面的语句加载配置:
NutConf.load("配置文件");
//加载自定义函数配置, 必须!因为默认情况下, CustomMake只在static{}块中加载一次配置, 新添加的配置在static之后的话, 那么新添加的函数配置将不会生效!
CustomMake.init();
完成这两步后, 你就定义了你自己的函数. 看个trim的例子:
public class Trim implements RunMethod, Plugin{
//处理方法, fetchParam为函数的参数. 它会将EL中函数括号后的所有内容传递过来
public Object run(List<Object> fetchParam) {
if(fetchParam.size() <= 0){
throw new ElException("trim方法参数错误");
}
String obj = (String) fetchParam.get(0);
return obj.trim();
}
//是否可以执行
public boolean canWork() {
return true;
}
//在EL表达式中的函数名
public String fetchSelf() {
return "trim";
}
}
还有些什么功能?
其实我们的 EL 很强悍的, 有好多功能, 好多使用技巧等待着你的发现. 现在简单的罗列一下, EL中的一些特性吧.
忠于 Java
Nutz中的 EL 完全忠实于 JAVA 基本运算规则, 并没有做一些扩展, 比如最常见的, 数据类型转换,在 JAVA 中进行数值运算的过程中, 是根据运算符两边的类型而最终决定运算结果的类型的, 比如:
7/3 // 将返回int型
而
(1.0 * 7)/3 // 返回double
(1.0f * 7)/3 // 则返回float
为什么后面两个返回类型不一样呢? 因为在 JAVA 中默认浮点类型是 double 哦.
基于这个原因, 在 EL 中同样保留了这些特点. 所以, 亲, 要是没返回 double 别骂我们哦~~~
支持对象方法调用
亲, EL 支持对象, 支持对象方法调用哦~~~
这有什么好大不了的? 给你看个例子, 嘿嘿:
Context context = Lang.context();
context.set("a", new BigDecimal("7"));
context.set("b", new BigDecimal("3"));
assertEquals(10, El.eval(context, "a.add(b).intValue()"));
- 看到什么没? 对了, BigDecimal 你完全可以丢各种各样的对象到 context 里面去, 然后在 EL 中调用它们的方法.
-
然后你就进行各种各样的虐待, 皮鞭, 蜡烛, 想来啥来啥...额...太邪恶了...
- 同样, EL 是使用反射的, 所以会存在一些底层异常的问题.
支持静态方法调用
没看错, EL支持静态方法调用, 不过, 在调用之前你需要设置一个变量才行...
Context context = Lang.context();
context.set("strings", Strings.class);
assertEquals("nutz", El.eval(context, "strings.trim(\" nutz \")"));
一些表达式的例子
普通运算
System.out.println(El.eval("3+2*5"));
// 输出为 13
字符串操作
System.out.println(El.eval("trim(\" abc \")"));
// 输出为 abc
Java 对象属性访问调用
Context context = Lang.content();
Pet pet = new Pet();
pet.setName("GFW");
context.set("pet",pet);
System.out.println(El.eval(context,"pet.name"));
// 输出为 GFW
函数调用
Context context = Lang.content();
Pet pet = new Pet();
context.set("pet",pet);
El.eval(context, "pet.setName('XiaoBai')");
System.out.println(El.eval(context,"pet.getName()"));
// 输出为 XiaoBai
数组访问
Context context = Lang.content();
context.set("x",Lang.array("A", "B", "C"));
System.out.println(El.eval(context,"x[0].toLowerCase()"));
// 输出为 a
列表访问
Context context = Lang.content();
context.set("x",Lang.list("A", "B", "C"));
System.out.println(El.eval(context,"x[0].toLowerCase()"));
// 输出为 a
Map 访问
Context context = Lang.content();
context.set("map",Lang.map("{x:10, y:5}"));
System.out.println(El.eval(context,"map['x'] * map['y']"));
// 输出为 50
判断
Context context = Lang.content();
context.set("a",5);
System.out.println(El.eval(context,"a>10"));
// 输出为 false
context.set("a",20);
System.out.println(El.eval(context,"a>10"));
// 输出为 true
相关推荐
Fel Java表达式引擎是一款轻量级且高效的开源表达式计算引擎。它的全称是FastExpressionLanguage,专门设计用于满足不断变化的功能需求和性能需求。Fel的执行方式主要依赖于函数,运算符如加减乘除等被视为Fel函数,...
**Fel表达式计算引擎0.9版本** Fel引擎,全称为Fast Expression Language,是一个轻量级、高性能的表达式计算引擎。在0.9版本中,它提供了强大的动态计算功能,使得开发者能够在运行时评估复杂的逻辑和数学表达式。...
**Fel表达式引擎详解** Fel(Fast Expression Language)是一种轻量级、高性能的表达式语言,主要用于在应用程序中进行动态计算和数据操作。它提供了一种简洁的语法,使得开发者可以方便地在运行时评估表达式,从而...
### 高速 Fel表达式引擎知识点详解 #### 一、Fel表达式引擎概述 Fel(Fast Expression Language)是一种高性能的表达式引擎,旨在满足企业级应用对于表达式处理的需求。它具备快速执行的能力,与ognl等其他流行...
说明:网上找了一圈表达式解析引擎实现的功能都不够满足支持业务需求,于是自己造轮子实现了一个,包含了等式,不等式,逻辑运算,参数,函数的支持。功能应该能够满足所有的业务需求了,函数可自行扩展,有需要支持...
说明:网上找了一圈表达式解析引擎实现的功能都不够满足支持业务需求,于是自己造轮子实现了一个,包含了等式,不等式,逻辑运算,参数,函数的支持。功能应该能够满足所有的业务需求了,函数可自行扩展,有需要支持...
免费好用的正则表达式引擎!! 完全免费 完全使用模版库编写,支持 char, wchar_t, int 等以及其他基类型版本。 全部代码位于一个头文件(.h)中, 比任何引擎都使用简单和方便。 支持从右向左匹配模式,可从文本...
正则表达式引擎是计算机科学中的一个重要组成部分,主要用于文本匹配和搜索。在本项目中,我们看到一个Python实现的简化版正则表达式引擎,它只支持基础的运算符,如括号、点号、星号、加号、问号和竖线。接下来,...
"Fel表达式引擎" Fel表达式引擎是一种高性能的表达式引擎,支持编译执行和解释执行两种模式。它可以处理海量数据,执行速度基本与Java字节码执行速度一样快。 1. FelEngine的使用 FelEngine是Fel表达式引擎的核心...
DEELX正则表达式引擎(v1.2)是一个高度优化且兼容Perl的C++实现的正则表达式库,旨在为开发者提供强大的文本匹配和处理能力。它源自RegExLab的研究开发项目,该团队致力于深入探索和改进正则表达式的性能和易用性。...
《DeelX正则表达式引擎及手册》是专为C语言开发人员提供的一款强大的正则表达式处理工具。这个压缩包包含两部分核心内容:Deelx的帮助文档(deelx_zh.chm)和引擎头文件(deelx.h)。通过深入理解这些资源,开发者...
**IKExpression简易表达式引擎V2.0**是一款强大的、轻量级的Java库,用于解析和执行基于字符串的表达式。它适用于那些需要在运行时动态计算的场景,例如在业务逻辑中进行条件判断、数据计算等。下面将详细介绍这款...
DEELX 是一个在 C++ 环境下的与 Perl 兼容的正则表达式引擎。是 RegExLab 开展的一个研究开发项目。 基本特点: 支持与 Perl 兼容的正则表达式语法。 支持 IGNORECASE, SINGLELINE, MULTILINE 等常见匹配模式。 ...
规则引擎的核心概念包括规则、规则包、规则库和表达式规则。 规则引擎的主要作用是将业务逻辑从应用程序代码中分离出来,使其更易于维护和更新。在传统的数据库操作中,我们通常使用SQL语句来处理数据的增删改查,...
Fel在源自于企业项目,设计目标是为了满足不断变化的功能需求和性能需求。 Fel是开放的,引擎执行中的多个模块都可以扩展或替换。Fel的执行主要是通过函数实现,运算符(+、-等...表达式引擎QQ群:75055831,欢迎交流。
DEELX 是一个在 C++ 环境下的与 Perl 兼容的正则表达式引擎。是 RegExLab 开展的一个研究开发项目。掌握DEELX,对于在VC++中使用正则表达式帮助很大,DEELX支持与 Perl 兼容的正则表达式语法。 支持 IGNORECASE, ...
DEELX 正则表达式引擎(v1.2) DEELX 正则表达式引擎(v1.2)
DEELX正则表达式引擎是一款专为处理和解析正则表达式而设计的强大引擎,它在编程领域中被广泛用于文本匹配、搜索和替换等任务。正则表达式(Regular Expression,简称regex)是一种模式匹配语言,允许我们用简洁的...
本文将深入探讨正则表达式的基本概念、不同类型的正则表达式引擎,以及它们的内部工作机制。 1. 什么是正则表达式 正则表达式(Regular Expression,简称regex)是一串由字符和特殊符号组成的字符串,用来定义一个...
【作品名称】:基于C++实现的正则表达式引擎,支持子表达式,反向引用,简单的预查语法,一些字符类,非贪婪匹配和边界匹配 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程...