java实现简单的字符串解析匹配运算规则引擎
Posted 天涯泪小武
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java实现简单的字符串解析匹配运算规则引擎相关的知识,希望对你有一定的参考价值。
有这样的需求,我有一个map,里面放了一些key-value,自定义了一些规则,如age==24&&name==aom||phone==123456789,希望能有个引擎能判断出这个Map里的值,是否匹配上这个规则,规则里有一些简单的运算,如==、contains等。
规则是动态可变的,这样就可以灵活控制命中了规则的数据能进行一些采集。
我做了一个这样简单的工具,目前可以支持
//规则描述,支持的有:
//==,如 age==25,name==jerry,字符串也不要加引号
//!=,和==一样的用法
//&&、||,如age==24&&name==aom||phone==123456789,不要加括号,自行调整好顺序
//contains,如address contains(example),字符串不要加引号
//matches,如phone matches(\\d+),正则表达式
//in,是否在一个集合里,如age in [12,1,25],集合需要用[]包围,字符串不要引号
//isEmpty,是否为空,如address isEmpty
//isNotEmpty,同isEmpty
//!(),取非操作,如 !(address isNotEmpty),注意,!必须在最前面,要取非的,需要用小括号包围
这些常用的一些基本规则。
类似于的表达式还有spring的SpEL、mvel这些表达式引擎,但我的场景对性能的要求相当苛刻,规则倒是很简单,是无法接受这些动态规则引擎的高达十几甚至20ms的耗时。对这一个规则匹配的耗时要求不能超过1ms,所以就自己做了一个。
下面是代码
import java.util.Map;
/**
* 规则校验器
* @author wuweifeng wrote on 2023/3/7
* @version 1.0
*/
public class RuleValidator
public static boolean validateRule(String rule, Map<String, String> variables)
if (rule == null || "".equals(rule))
return false;
// 去除所有空格
rule = rule.replaceAll("\\\\s+", "");
//判断表达式是不是取非语句,如" !(a==345) "
if (rule.startsWith("!(") && rule.endsWith(")"))
return !validateRule(rule.substring(2, rule.length() - 1), variables);
// 处理 || 运算符
if (rule.contains("||"))
int index = rule.indexOf("||");
String left = rule.substring(0, index);
String right = rule.substring(index + 2);
return validateRule(left, variables) || validateRule(right, variables);
// 处理 && 运算符
if (rule.contains("&&"))
int index = rule.indexOf("&&");
String left = rule.substring(0, index);
String right = rule.substring(index + 2);
return validateRule(left, variables) && validateRule(right, variables);
// 处理括号运算符
if (rule.startsWith("(") && rule.endsWith(")"))
String subrule = rule.substring(1, rule.length() - 1);
return validateRule(subrule, variables);
// 处理 == 运算符和 != 运算符
if (rule.contains("=="))
int index = rule.indexOf("==");
String left = rule.substring(0, index);
String right = rule.substring(index + 2);
if (variables.containsKey(left))
return variables.get(left).equals(right);
else
return left.equals(right);
else if (rule.contains("!="))
int index = rule.indexOf("!=");
String left = rule.substring(0, index);
String right = rule.substring(index + 2);
if (variables.containsKey(left))
return !variables.get(left).equals(right);
else
return !left.equals(right);
// 处理 contains 运算符和 in 运算符
if (rule.contains("contains"))
int index = rule.indexOf("contains");
String left = rule.substring(0, index).replace(".", "");
String value = variables.get(left);
String right = rule.substring(index + 8).replace("(", "").replace(")", "");
if (variables.containsKey(left))
return value.contains(right);
else
return false;
else if (rule.contains("in"))
int index = rule.indexOf("in");
String left = rule.substring(0, index);
String value = variables.get(left);
String right = rule.substring(index + 2).replace("[", "").replace("]", "");
if (variables.containsKey(right))
String[] items = variables.get(right).split(",");
for (String item : items)
if (item.trim().equals(value))
return true;
return false;
else
String[] items = right.split(",");
for (String item : items)
if (item.trim().equals(value))
return true;
return false;
// 处理 isEmpty 运算符
if (rule.contains("isEmpty"))
int index = rule.indexOf("isEmpty");
String left = rule.substring(0, index);
if (variables.containsKey(left))
return variables.get(left) == null || "".equals(variables.get(left));
else
return false;
// 处理 isEmpty 运算符
if (rule.contains("isNotEmpty"))
int index = rule.indexOf("isNotEmpty");
String left = rule.substring(0, index);
if (variables.containsKey(left))
return variables.get(left) != null && !"".equals(variables.get(left));
else
return false;
// 处理 matches 运算符
if (rule.contains("matches"))
int index = rule.indexOf("matches");
String left = rule.substring(0, index);
String right = rule.substring(index + 7);
if (variables.containsKey(left))
return variables.get(left).matches(right);
else
return left.matches(right);
// 如果规则字符串为变量名,则直接查找Map中对应的值
if (variables.containsKey(rule))
return true;
return false;
import java.util.HashMap;
import java.util.Map;
/**
* @author wuweifeng wrote on 2023/3/7
* @version 1.0
*/
public class RuleValidatorTest
//规则描述,支持的有:
//==,如 age==25,name==jerry,字符串也不要加引号
//!=,和==一样的用法
//&&、||,如age==24&&name==aom||phone==123456789,不要加括号,自行调整好顺序
//contains,如address contains(example),字符串不要加引号
//matches,如phone matches(\\d+),正则表达式
//in,是否在一个集合里,如age in [12,1,25],集合需要用[]包围,字符串不要引号
//isEmpty,是否为空,如address isEmpty
//isNotEmpty,同isEmpty
//!(),取非操作,如 !(address isNotEmpty),注意,!必须在最前面,要取非的,需要用小括号包围
public static void main(String[] args)
// 初始化变量Map
Map<String, String> variables = new HashMap<>();
variables.put("name", "Tom");
variables.put("age", "25");
variables.put("email", "tom@example.com");
variables.put("phone", "123456789");
variables.put("address", "");
// 测试用例
String rule1 = "age==25";
String rule2 = "age!=25";
String rule3 = "age==30";
String rule4 = "age!=30";
String rule5 = "age==24&&name==aom||phone==123456789";
String rule6 = "age==25||name==Jerry";
String rule7 = "address contains(example)";
//正则表达式
String rule8 = "phone matches(\\\\d+)";
String rule9 = "age in [12,1,25]";
String rule10 = "age in [12,1,25] && name==Tom";
String rule11 = "address isEmpty";
String rule12 = "address isNotEmpty";
String rule13 = "!(address isNotEmpty)";
// 断言
System.out.println("rule1-" + RuleValidator.validateRule(rule1, variables));
System.out.println("rule2-" + RuleValidator.validateRule(rule2, variables));
System.out.println("rule3-" + RuleValidator.validateRule(rule3, variables));
System.out.println("rule4-" + RuleValidator.validateRule(rule4, variables));
System.out.println("------");
System.out.println("rule5-" + RuleValidator.validateRule(rule5, variables));
System.out.println("rule6-" + RuleValidator.validateRule(rule6, variables));
System.out.println("rule7-" + RuleValidator.validateRule(rule7, variables));
System.out.println("------");
System.out.println("rule8-" + RuleValidator.validateRule(rule8, variables));
System.out.println("------");
System.out.println("rule9-" + RuleValidator.validateRule(rule9, variables));
System.out.println("rule10-" + RuleValidator.validateRule(rule10, variables));
System.out.println("rule11-" + RuleValidator.validateRule(rule11, variables));
System.out.println("rule12-" + RuleValidator.validateRule(rule12, variables));
System.out.println("rule13-" + RuleValidator.validateRule(rule13, variables));
整体比较简单,不支持复杂的(),最好是平铺的一些规则。
以上是关于java实现简单的字符串解析匹配运算规则引擎的主要内容,如果未能解决你的问题,请参考以下文章