如何让Apache Commons JEXL表达式匹配正则表达式数组?
自定义Apache Commons JEXL
=~ 运算符实现正则数组匹配 Apache Commons JEXL 提供的=~(In or Match)运算符默认有两种行为:
- 当右侧为字符串时,作为正则匹配器工作:
"abcdef" =~ "abc.*" - 当右侧为字符串数组时,作为包含运算符工作(判断左侧字符串是否在数组中):
"a" =~ ["a","b","c","d","e","f"]
但默认不支持右侧数组元素作为正则表达式匹配的场景,比如"abcdef" =~ ["abc.*", "a.d.*"]预期返回true,但默认逻辑会判断字面量是否相等,因此返回false。以下是实现该特性的方法:
一、通过Java代码修改JexlEngine
核心思路是自定义JexlOperatorStrategy,重写=~运算符的处理逻辑,当右侧为数组/集合时,遍历其中的字符串作为正则表达式匹配左侧内容。
1. 自定义运算符策略类
import org.apache.commons.jexl3.*; import java.util.Collection; import java.util.regex.Pattern; public class RegexArrayOperatorStrategy extends JexlOperatorStrategy { private final JexlOperatorStrategy delegate; public RegexArrayOperatorStrategy(JexlOperatorStrategy delegate) { this.delegate = delegate; } @Override public Object evaluate(JexlOperator op, Object lhs, Object rhs) { // 仅处理=~(MATCH)运算符 if (op == JexlOperator.MATCH) { // 左侧必须是字符串类型 if (lhs instanceof String strLhs) { // 处理数组类型的右侧 if (rhs instanceof Object[] arrRhs) { for (Object obj : arrRhs) { if (obj instanceof String regex) { if (Pattern.matches(regex, strLhs)) { return true; } } } return false; } // 处理集合类型的右侧(比如List) else if (rhs instanceof Collection<?> colRhs) { for (Object obj : colRhs) { if (obj instanceof String regex) { if (Pattern.matches(regex, strLhs)) { return true; } } } return false; } } } // 其他情况沿用默认运算符逻辑 return delegate.evaluate(op, lhs, rhs); } }
2. 配置并使用自定义引擎
// 创建带有自定义运算符策略的JexlEngine JexlEngine jexl = new JexlBuilder() .operatorStrategy(new RegexArrayOperatorStrategy(JexlEngine.DEFAULT_STRATEGY)) .create(); // 测试正则数组匹配表达式 JexlExpression expr = jexl.createExpression("\"abcdef\" =~ [\"abc.*\", \"a.d.*\"]"); Object result = expr.evaluate(null); System.out.println(result); // 输出true
二、在JEXL表达式中的使用
配置好自定义引擎后,表达式写法无需额外修改,直接使用数组语法即可:
# 匹配数组中任意一个正则表达式 "abcdef" =~ ["abc.*", "a.d.*"] # 支持带正则标志的写法(比如忽略大小写) "ABCDEF" =~ ["(?i)abc.*", "a.d.*"]
若数组中包含非字符串元素,自定义策略会跳过该元素,继续匹配其他正则表达式;若所有元素都不匹配,则返回false。
内容的提问来源于stack exchange,提问作者queeg
相关产品推荐
相关产品推荐

