简单bool表达式解析(编译原理)在值映射业务中的运用

业务当中,需要将多方来源的项值转换为几套统一的项值。

原有实现逻辑:使用一份json格式的规则,由专门开发的一段程序匹配

image.png

存在的问题:
-支持的映射规则并不丰富(多值全与、多值全或、默认)
-规则配置内容较长、不易读

改进后的命中表达式:如!(1120101001&1120101002)|1120101003

功能:
-输入值的与、或、非运算规则
-括号中可写子式

翻译方案

exp -> node & {if (!context.result) return false} exp
    -> node | {if (context.result) return true} exp
    -> node {return context.result}

node -> ! {context.not ^= true} node
     -> (exp) {context.result = context.not ^ judge(exp); context.not = false;}
     -> factor

factor -> num {context.result = context.not ^ valueSet.contains(num); context.not = false;}

实际代码

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

public class HitRuleHelper {
    public static boolean judge(String hitRule, HashSet valueSet) {
        IRuleReader reader = new IRuleReader() {
            int offset = 0;
            @Override
            public Character next() {
                if (hitRule.length() <= offset) {
                    return null;
                }
                char ret = hitRule.charAt(offset);
                offset++;
                return ret;
            }
        };
        return judgeInner(reader, valueSet, null);
    }

    private static boolean judgeInner(IRuleReader reader, HashSet valueSet, Character endChar) {
        Context context = new Context();
        context.reader = reader;
        context.valueSet = valueSet;
        Character curChar = null;
        while (!context.readEnd) {
            curChar = reader.next();
            if (null != curChar) {
                IOper oper = nextOper.get((100 * allChars.indexOf(curChar)) + context.status);
                if (null != oper) {
                    oper.doWith(context);
                }
                Integer newStatus = nextStatus.get((100 * allChars.indexOf(curChar)) + context.status);
                if (null != newStatus) {
                    context.status = newStatus;
                }
            } else {
                if (1 == context.status) {
                    context.result = context.valueSet.contains(context.curItemId) ^ context.not;
                }
                context.readEnd = true;
            }
        }
        if (null != endChar) {
            while (null != curChar && !endChar.equals(curChar)) {
                curChar = reader.next();
            }
        }
        return context.result;
    }

    private static List allChars = Arrays.asList('0','1','2','3','4','5','6','7','8','9','!','&','|','(',')');

    private static HashMap nextStatus = new HashMap<>();
    private static HashMap nextOper = new HashMap<>();

    static {
        nextOper.put((100 * allChars.indexOf('!')), context -> context.not = !context.not);
        nextOper.put((100 * allChars.indexOf('(')), context -> {
            context.result = judgeInner(context.reader, context.valueSet, ')') ^ context.not;
            context.not = false;
        });
        nextStatus.put((100 * allChars.indexOf('(')), 2);

        for (int i = 0; i < 10; i++) {
            long numFinal = i;
            nextOper.put((100 * i), context -> context.curItemId = (context.curItemId * 10L) + numFinal);
            nextOper.put((100 * i) + 1, context -> context.curItemId = (context.curItemId * 10L) + numFinal);
            nextStatus.put((100 * i), 1);

        }
        nextOper.put((100 * allChars.indexOf('&')) + 1, context -> {
            context.itemResult = context.valueSet.contains(context.curItemId) ^ context.not;
            context.not = false;
            context.curItemId = 0L;
            if (!context.itemResult) {
                context.result = false;
                context.readEnd = true;
            }
        });
        nextStatus.put((100 * allChars.indexOf('&') + 1), 0);


        nextOper.put((100 * allChars.indexOf('|') + 1), context -> {
            context.itemResult = context.valueSet.contains(context.curItemId) ^ context.not;
            context.not = false;
            context.curItemId = 0L;
            if (context.itemResult) {
                context.result = true;
                context.readEnd = true;
            }
        });
        nextStatus.put((100 * allChars.indexOf('|') + 1), 0);

        nextOper.put((100 * allChars.indexOf('&')) + 2, context -> {
            if (!context.result) {
                context.readEnd = true;
            }
        });
        nextStatus.put((100 * allChars.indexOf('&') + 2), 0);


        nextOper.put((100 * allChars.indexOf('|') + 2), context -> {
            if (context.result) {
                context.readEnd = true;
            }
        });
        nextStatus.put((100 * allChars.indexOf('|') + 2), 0);


        nextOper.put((100 * allChars.indexOf(')')) + 1, context -> {
            context.result = context.valueSet.contains(context.curItemId) ^ context.not;
            context.readEnd = true;
        });
        nextOper.put((100 * allChars.indexOf(')')) + 2, context -> {
            context.readEnd = true;
        });
    }

    interface IOper {
        void doWith(Context context);
    }

    static class Context {
        IRuleReader reader;
        HashSet valueSet;
        int status = 0;
        boolean result = false;
        boolean readEnd = false;
        boolean not = false;
        boolean itemResult = false;
        long curItemId = 0L;
    }

    interface IRuleReader {
        Character next();
    }
}

你可能感兴趣的:(简单bool表达式解析(编译原理)在值映射业务中的运用)