前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java实现简单的字符串解析匹配运算规则引擎

java实现简单的字符串解析匹配运算规则引擎

作者头像
天涯泪小武
发布2023-03-09 21:13:13
7830
发布2023-03-09 21:13:13
举报
文章被收录于专栏:SpringCloud专栏SpringCloud专栏

有这样的需求,我有一个map,里面放了一些key-value,自定义了一些规则,如age==24&&name==aom||phone==123456789,希望能有个引擎能判断出这个Map里的值,是否匹配上这个规则,规则里有一些简单的运算,如==、contains等。

规则是动态可变的,这样就可以灵活控制命中了规则的数据能进行一些采集。

我做了一个这样简单的工具,目前可以支持

代码语言:javascript
复制
//规则描述,支持的有:
    //==,如 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,所以就自己做了一个。

下面是代码

代码语言:javascript
复制
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;

    }
}
代码语言:javascript
复制
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));
    }
}

整体比较简单,不支持复杂的(),最好是平铺的一些规则。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-03-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档