字符串处理--->逻辑表达式转可执行脚本字符串

发布时间 2023-04-19 09:36:26作者: 米豪
  /**
     * 执行函数脚本
     *
     * @since author: l00050286 date: 2023/4/10 15:26
     * @param scriptStr 函数脚本字符串
     * @param functionName 函数名
     * @return java.lang.Object
    */
    public static Object executeFunctionScript(String scriptStr,String functionName) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
        engine.eval(scriptStr);
        Invocable jsInvoke = (Invocable) engine;
        return jsInvoke.invokeFunction(functionName);
    }
    
    /**
     * 获取可执行函数Str
     *
     * @since author: l00050286 date: 2023/4/10 14:46
     * @param sourceFormula 计算规则
     * @param endSign 计算规则结束标识
     * @param functionName 可执行函数名称
     * @param factorValueMap 计算规则计算因子的值
     * @return java.lang.String
    */
    public static String getScriptStr(String sourceFormula, String endSign, String functionName,
                                      Map<String, String> factorValueMap) {
        int length = endSign.length();
        String column = StringUtils.trimAllWhitespace(sourceFormula);
        String splitStr = "IF|THEN|OTHERWISE|AND|OR|>=|<=|>|<|==|\\+|-|\\*|/|\\?|:";
        if (column.indexOf("IF") == 0) {
            String logicScript = column.substring(0, column.length() - length); // 去掉结束标记
            Map<String, String> factorMap = new HashMap<>();
            // 1、设置需要替换的最小计算因数
            setFactorMap(factorMap, logicScript, splitStr);
            // 2、格式化逻辑脚本
            splitStr = "IF|THEN|OTHERWISE|AND|OR|>=|<=|>|<|==|\\+|-|\\*|/|\\;|\\?|:|" + endSign;
            String formatFormula = CommonUtil.formatLogicFormula(column, endSign, splitStr);
            // 3、格式化逻辑脚本转换成可执行函数
            return scriptTransferFunction(formatFormula, factorMap, functionName, endSign, factorValueMap);
        } else {
            Map<String, String> factorMap = new HashMap<>();
            // 1、设置需要替换的最小计算因数
            setFactorMap(factorMap, column, splitStr);
            // 2、格式化逻辑脚本
            splitStr = "IF|THEN|OTHERWISE|AND|OR|>=|<=|>|<|==|\\+|-|\\*|/|\\;|\\?|:|" + endSign;
            String formatFormula = CommonUtil.formatLogicFormula(column, endSign, splitStr);
            // 3、格式化逻辑脚本转换成可执行函数
            return scriptTransferFunction(formatFormula, factorMap, functionName, endSign, factorValueMap);
        }
    }

    /**
     * 设置需要替换的最小计算因数
     *
     * @since author: l00050286 date: 2023/4/10 14:40
     * @param factorMap 保存需要替换的最小计算因数Map
     * @param logicScript 逻辑脚本
     * @param splitStr 分隔符
     * @return void
    */
    public static void setFactorMap(Map<String,String> factorMap,String logicScript,String splitStr){
        String[] elementArray = logicScript.split(";");
        int serialIndex=0;
        // 解析公式获取需要替换的最小计算因数
        for (String tempElement : elementArray) {
            String[] split = tempElement.split(splitStr);
            for (String minCalculationFactor : split) {
                if(!CommonUtil.isEmpty(minCalculationFactor)){
                    int j = minCalculationFactor.indexOf("[");
                    int k = minCalculationFactor.indexOf("]");
                    if (j > -1 && k > -1) {
                        // 考虑到 ( ) 的情况
                        int l = minCalculationFactor.indexOf(")");

                        String element = (l > -1 ? minCalculationFactor.substring(j, l) : minCalculationFactor.substring(j));
                        if(factorMap.get(element) == null) {
                            serialIndex++;
                            factorMap.put(element, "param" + serialIndex);
                            // 考虑到存在()的情况
                            int m = minCalculationFactor.indexOf("(");
                            if (m > -1 || l > -1) {
                                factorMap.put(minCalculationFactor, element);
                            }
                        }else{
                            // 考虑到(,((,(((...和),)),)))...的情况
                            if(factorMap.get(minCalculationFactor) == null){
                                factorMap.put(minCalculationFactor, element);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 格式化逻辑公式
     *
     * @since author: l00050286 date: 2023/3/31 18:28
     * @param column 计算规则公式
     * @param endSign 原始字符串结束标识
     * @param splitStr 分隔字符串
     *                 "IF|THEN|OTHERWISE|AND|OR|>=|<=|>|<|==|\\+|-|\\*|/|\\;|"
     *                 "IF|THEN|OTHERWISE|AND|OR|>=|<=|>|<|==|\\+|-|\\*|/"
     * @return java.lang.String
     */
    public static String formatLogicFormula(String column,String endSign,String splitStr) {
        List<String> separatorList = new ArrayList<>();
        String[] split1 = column.split(splitStr);
        int i = 0;
        int j = 1;
        int length = split1.length;
        while (column.length() > 0 && i < length && j < length) {
            column = column.substring(split1[i].length());
            int i1 = column.indexOf(split1[j]);
            separatorList.add(column.substring(0, i1));
            column = column.substring(i1);
            i++;
            j++;
        }
        StringBuilder stringBuilder = new StringBuilder();
        int size = separatorList.size();
        for (int i1 = 0; i1 < length; i1++) {
            if(!CommonUtil.isEmpty(split1[i1])){
                stringBuilder.append(split1[i1]).append(" ");
            }
            if (i1 < size) {
                String tmp = separatorList.get(i1);
                if(tmp.length()>1 && tmp.indexOf(";")==0){
                    stringBuilder.append(";").append(" ").append(tmp.substring(1)).append(" ");
                }else{
                    stringBuilder.append(separatorList.get(i1)).append(" ");
                }
            }
        }
        stringBuilder.append(endSign);
        return stringBuilder.toString();
    }

    /**
     * 格式化逻辑脚本转换成可执行函数
     *
     * @since author: l00050286 date: 2023/4/10 15:05
     * @param formatFormula 格式化逻辑脚本
     * @param factorMap 需要替换的最小计算因数Map
     * @param functionName 可执行函数名称
     * @param endSign 格式化逻辑脚本结束标识
     * @return java.lang.String
    */
    public static String scriptTransferFunction(String formatFormula, Map<String, String> factorMap,
                                                String functionName, String endSign,
                                                Map<String, String> factorValueMap) {
        String[] elementAllArray = formatFormula.split(" ");
        StringBuilder stringBuilderFormula = new StringBuilder();
        factorMap.forEach((key, value) -> {
            if (key.indexOf("(") == -1 && key.indexOf(")") == -1) {
                if (factorValueMap.get(key) == null) {
                    stringBuilderFormula.append("var ").append(value).append(" = 10;\n");
                } else {
                    stringBuilderFormula.append("var ").append(value).append(" = ").append(factorValueMap.get(key)).append(";\n");
                }
            }
        });
        stringBuilderFormula.append("function ");
        if (formatFormula.indexOf("IF") == 0) {
            stringBuilderFormula.append(functionName).append("(){\n var result = 0;\n");
        } else {
            stringBuilderFormula.append(functionName).append("(){\n var result = ( \n");
        }

        for (String element : elementAllArray) {
            switch (element) {
                case "IF":
                    stringBuilderFormula.append(" if (");
                    break;
                case "THEN":
                    stringBuilderFormula.append(") {\n\t result = ");
                    break;
                case "AND":
                    stringBuilderFormula.append(" && ");
                    break;
                case "OR":
                    stringBuilderFormula.append(" || ");
                    break;
                case "OTHERWISE":
                    stringBuilderFormula.append(";\n } else {\n\t result = ");
                    break;
                case ";":
                    stringBuilderFormula.append(";\n } else");
                    break;
                default:
                    if (factorMap.get(element) == null) {
                        if (element.equals(endSign)) {
                            if(formatFormula.indexOf("IF") == 0){
                                stringBuilderFormula.append(";\n }\n return result ;\n}");
                            } else{
                                stringBuilderFormula.append(" );\n return result ;\n}");
                            }
                        } else {
                            stringBuilderFormula.append(" ").append(element);
                        }
                    } else {
                        String factor = factorMap.get(element);
                        String parameter = factorMap.get(factor);
                        if (parameter != null) {
                            element = element.replace(factor, parameter);
                            stringBuilderFormula.append(element);
                        } else {
                            stringBuilderFormula.append(" ").append(factorMap.get(element));
                        }
                    }
                    break;
            }
        }
        return stringBuilderFormula.toString();
    }