package com.chinaztt.mes.quality.utils; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.chinaztt.mes.quality.dto.ReportSampleItemDTO; import com.chinaztt.mes.quality.entity.ReportSampleItem; import com.chinaztt.mes.quality.entity.TestStandardParam; import lombok.AllArgsConstructor; import org.apache.commons.lang3.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; /** * @Author: cxf * @Date: 2021/09/07 16:00 */ @Service @AllArgsConstructor public class AutoJudgmentUtils { private static final Logger logger = LoggerFactory.getLogger(AutoJudgmentUtils.class); private static final ScriptEngineManager manager = new ScriptEngineManager(); /** * 运算包括: * 1.正常运算 + - * || && 以及x==true */ public static Boolean computeExpression(String expression,String hintMsg) { Matcher valueMatcher = FunctionConfig.PATTEN_VALUE.matcher(expression); if (valueMatcher.find()) { logger.error(expression); throw new RuntimeException("公式存在不能处理的检测项:" + valueMatcher.group() + " -> 表达式 = 【" + expression + "】明细行检测项编号 = " + hintMsg); } ScriptEngine se = manager.getEngineByName("js"); String[] split; Boolean bl = false; Boolean eval; expression = expression.replace("≥", ">="); expression = expression.replace("≤", "<="); expression = expression.replace(";", ";"); try { split = expression.split(";"); for (int i = 0; i < split.length; i++) { String s = split[i]; eval = (Boolean) se.eval(s); bl = bl || eval; } } catch (ScriptException e) { logger.error(expression); throw new RuntimeException("执行判定表达式 = 【" + expression + "】失败 -> 明细行检测项编号 = " + hintMsg); } return bl; } /** * 求值运算包括: * 1.正常运算 + - * || && 以及x==true */ public static String computeResult(String expression) throws Exception { ScriptEngine se = manager.getEngineByName("js"); String result = ""; expression = expression.replace("≥", ">="); expression = expression.replace("≤", "<="); expression = expression.replace(";", ";"); // try { result = se.eval(expression).toString(); // } catch (ScriptException e) { // logger.error(expression); // throw new RuntimeException("公式不规范,无法执行:" + expression); // } return result; } /** * 处理公式 * * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ public static String replace(String judgeFormula, List reportSampleItemList) { judgeFormula = replacePassFunction(judgeFormula, reportSampleItemList); judgeFormula = replacePassAllFunction(judgeFormula, reportSampleItemList); judgeFormula = replaceAvgFunction(judgeFormula, reportSampleItemList); judgeFormula = replaceMaxFunction(judgeFormula, reportSampleItemList); judgeFormula = replaceMinFunction(judgeFormula, reportSampleItemList); judgeFormula = replacePiFunction(judgeFormula, reportSampleItemList); judgeFormula = replaceSqrtFunction(judgeFormula, reportSampleItemList); judgeFormula = replacePowFunction(judgeFormula, reportSampleItemList); judgeFormula = replaceLogFunction(judgeFormula, reportSampleItemList); judgeFormula = replaceLnFunction(judgeFormula, reportSampleItemList); judgeFormula = replaceSTDValue(judgeFormula, reportSampleItemList); judgeFormula = replaceValue(judgeFormula, reportSampleItemList); return judgeFormula; } /** * 所有检测项都通过函数 * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ private static String replacePassAllFunction(String judgeFormula, List reportSampleItemList) { Matcher passAllMatcher = FunctionConfig.PATTEN_PASSALL.matcher(judgeFormula); List passAllFunctionList = new ArrayList(); addMatcherGroup(passAllFunctionList, passAllMatcher); if (CollectionUtil.isNotEmpty(passAllFunctionList)) { boolean flag = true; for (ReportSampleItem reportSampleItem : reportSampleItemList) { if (!reportSampleItem.getIsQualified()) { flag = false; break; } } judgeFormula = judgeFormula.replace(judgeFormula, flag+""); } // 这边再判断比对一下,预防不规范的写法 passAllMatcher = FunctionConfig.PATTEN_PASSALL.matcher(judgeFormula); passAllFunctionList = new ArrayList(); addMatcherGroup(passAllFunctionList, passAllMatcher); if (CollectionUtil.isNotEmpty(passAllFunctionList)) { throw new RuntimeException("公式存在无法处理的合格函数:" + judgeFormula); } return judgeFormula; } /** * 替换值-最小值函数 * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ private static String replaceMinFunction(String judgeFormula, List reportSampleItemList) { Matcher minMatcher = FunctionConfig.PATTEN_MIN.matcher(judgeFormula); List minFunctionList = new ArrayList(); addMatcherGroup(minFunctionList, minMatcher); if (CollectionUtil.isNotEmpty(minFunctionList)) { for (int i = 0; i < minFunctionList.size(); i++) { Matcher valueMatcher = FunctionConfig.PATTEN_VALUE.matcher(minFunctionList.get(i)); List valueList = new ArrayList(); addMatcherGroup(valueList, valueMatcher); // 平均值函数里面至少有一个参数项 if (CollectionUtil.isEmpty(valueList)) { throw new RuntimeException("公式不规范,最小值函数里面至少有一个参数项:" + minFunctionList.get(i)); } // 处理平均值函数,然后直接替换公式 List minItemList = new ArrayList(); for (int j = 0; j < valueList.size(); j++) { for (ReportSampleItem reportSampleItem : reportSampleItemList) { String coed = "V[" + reportSampleItem.getItemCode() + "]"; if (valueList.get(j).contains(coed)) { // 平均值函数,几个参数有值,就按几个去计算 if (StringUtils.isNotBlank(reportSampleItem.getItemValue())) { minItemList.add(reportSampleItem.getItemValue()); } break; } } } String replacement = ""; if (CollectionUtil.isNotEmpty(minItemList)) { replacement = Collections.min(minItemList); } else { replacement = "0"; } judgeFormula = judgeFormula.replace(minFunctionList.get(i), replacement); } } // 这边再判断比对一下,预防不规范的写法 minMatcher = FunctionConfig.PATTEN_MIN.matcher(judgeFormula); minFunctionList = new ArrayList(); addMatcherGroup(minFunctionList, minMatcher); if (CollectionUtil.isNotEmpty(minFunctionList)) { throw new RuntimeException("公式存在无法处理的最小值函数:" + judgeFormula); } return judgeFormula; } /** * 替换值-最大值函数 * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ private static String replaceMaxFunction(String judgeFormula, List reportSampleItemList) { Matcher maxMatcher = FunctionConfig.PATTEN_MAX.matcher(judgeFormula); List maxFunctionList = new ArrayList(); addMatcherGroup(maxFunctionList, maxMatcher); if (CollectionUtil.isNotEmpty(maxFunctionList)) { for (int i = 0; i < maxFunctionList.size(); i++) { Matcher valueMatcher = FunctionConfig.PATTEN_VALUE.matcher(maxFunctionList.get(i)); List valueList = new ArrayList(); addMatcherGroup(valueList, valueMatcher); // 平均值函数里面至少有一个参数项 if (CollectionUtil.isEmpty(valueList)) { throw new RuntimeException("公式不规范,最大值函数里面至少有一个参数项:" + maxFunctionList.get(i)); } // 处理平均值函数,然后直接替换公式 List avgItemList = new ArrayList(); for (int j = 0; j < valueList.size(); j++) { for (ReportSampleItem reportSampleItem : reportSampleItemList) { String coed = "V[" + reportSampleItem.getItemCode() + "]"; if (valueList.get(j).contains(coed)) { // 平均值函数,几个参数有值,就按几个去计算 if (StringUtils.isNotBlank(reportSampleItem.getItemValue())) { avgItemList.add(reportSampleItem.getItemValue()); } break; } } } String replacement = ""; if (CollectionUtil.isNotEmpty(avgItemList)) { replacement = Collections.max(avgItemList); } else { replacement = "0"; } judgeFormula = judgeFormula.replace(maxFunctionList.get(i), replacement); } } // 这边再判断比对一下,预防不规范的写法 maxMatcher = FunctionConfig.PATTEN_MAX.matcher(judgeFormula); maxFunctionList = new ArrayList(); addMatcherGroup(maxFunctionList, maxMatcher); if (CollectionUtil.isNotEmpty(maxFunctionList)) { throw new RuntimeException("公式存在无法处理的平均值函数:" + judgeFormula); } return judgeFormula; } /** * 替换值-π * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ private static String replacePiFunction(String judgeFormula, List reportSampleItemList) { // 将公式里的剩下的pi替换为π值 for (ReportSampleItem reportSampleItem : reportSampleItemList) { String coed = "pi"; if (judgeFormula.contains(coed)) { if (StringUtils.isBlank(reportSampleItem.getItemValue())) { throw new RuntimeException("参与计算的检测项值不能为空"); } else { judgeFormula = judgeFormula.replace(coed, String.valueOf(Math.PI)); } } } return judgeFormula; } /** * 开根号函数 * @param judgeFormula * @param reportSampleItemList * @return */ private static String replaceSqrtFunction(String judgeFormula, List reportSampleItemList) { Matcher sqrtMatcher = FunctionConfig.PATTEN_SQRT.matcher(judgeFormula); List sqrtFunctionList = new ArrayList(); addMatcherGroup(sqrtFunctionList, sqrtMatcher); if (CollectionUtil.isNotEmpty(sqrtFunctionList)) { for (int i = 0; i < sqrtFunctionList.size(); i++) { judgeFormula = judgeFormula.replace("sqrt", "Math.sqrt"); } } return judgeFormula; } /** * 平方函数 * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ private static String replacePowFunction(String judgeFormula, List reportSampleItemList) { Matcher powMatcher = FunctionConfig.PATTEN_POW.matcher(judgeFormula); List powFunctionList = new ArrayList(); addMatcherGroup(powFunctionList, powMatcher); if (CollectionUtil.isNotEmpty(powFunctionList)) { for (int i = 0; i < powFunctionList.size(); i++) { judgeFormula = judgeFormula.replace("pow", "Math.pow"); } } return judgeFormula; } /** * log函数 * @param judgeFormula * @param reportSampleItemList * @return */ private static String replaceLogFunction(String judgeFormula, List reportSampleItemList) { Matcher logMatcher = FunctionConfig.PATTEN_LOG.matcher(judgeFormula); List logFunctionList = new ArrayList(); addMatcherGroup(logFunctionList, logMatcher); if (CollectionUtil.isNotEmpty(logFunctionList)) { for (int i = 0; i < logFunctionList.size(); i++) { if (org.apache.commons.lang3.StringUtils.countMatches(logFunctionList.get(i), "(") > 1) { String substring = judgeFormula.substring(judgeFormula.indexOf(logFunctionList.get(i))); int number = org.apache.commons.lang3.StringUtils.countMatches(logFunctionList.get(i), "("); int last = org.apache.commons.lang3.StringUtils.ordinalIndexOf(substring, ")", number); String result = substring.substring(0, last + 1); judgeFormula = judgeFormula.replace(result, "Math.log" + result.substring(3) + "/Math.log(10)"); } else { judgeFormula = judgeFormula.replace(logFunctionList.get(i), "Math.log" + logFunctionList.get(i).substring(3) + "/Math.log(10)"); } } } return judgeFormula; } private static String replaceLnFunction(String judgeFormula, List reportSampleItemList) { Matcher lnMatcher = FunctionConfig.PATTEN_LN.matcher(judgeFormula); List lnFunctionList = new ArrayList(); addMatcherGroup(lnFunctionList, lnMatcher); if (CollectionUtil.isNotEmpty(lnFunctionList)) { for (int i = 0; i < lnFunctionList.size(); i++) { judgeFormula = judgeFormula.replace(lnFunctionList.get(i), "Math.log"); } } return judgeFormula; } /** * 获取标准值 * @param judgeFormula * @param reportSampleItemList * @return */ private static String replaceSTDValue(String judgeFormula, List reportSampleItemList) { Matcher stdMatcher = FunctionConfig.PATTEN_STD.matcher(judgeFormula); List stdFunctionList = new ArrayList(); addMatcherGroup(stdFunctionList, stdMatcher); if (CollectionUtil.isNotEmpty(stdFunctionList)) { for(String input : stdFunctionList){ Matcher valueMatcher = FunctionConfig.PATTEN_VALUE.matcher(input); List valueList = new ArrayList(); addMatcherGroup(valueList, valueMatcher); // STD函数里面至少有一个参数项 if (CollectionUtil.isEmpty(valueList)) { throw new RuntimeException("公式不规范,STD函数里面至少有一个参数项:" + input); } String param = valueList.get(0); for (ReportSampleItemDTO itemDTO : reportSampleItemList) { String coed = "V[" + itemDTO.getItemCode() + "]"; if (coed.equals(param)) { // 如果检测项值为数字类型直接替换,文字类型则增加单引号 if (NumberUtils.isCreatable(itemDTO.getItemValue())) { judgeFormula = judgeFormula.replace(input, itemDTO.getItemReference()); } else { judgeFormula = judgeFormula.replace(input, "'" + itemDTO.getItemReference() + "'"); } break; } } } } return judgeFormula; } /** * 替换值-普通参数项 * * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ public static String replaceValue(String judgeFormula, List reportSampleItemList) { // 将公式里的剩下的code替换为值 for (ReportSampleItem reportSampleItem : reportSampleItemList) { String coed = "V[" + reportSampleItem.getItemCode() + "]"; if (judgeFormula.contains(coed)) { if (StringUtils.isBlank(reportSampleItem.getItemValue())) { //throw new RuntimeException("检测项编号为" + reportSampleItem.getItemCode() + "参与计算的检测项值不能为空"); throw new RuntimeException("检测项编号=" + reportSampleItem.getItemCode() + "->检测值为空->公式无法引用"); } else { // 如果检测项值为数字类型直接替换,文字类型则增加单引号 if (NumberUtils.isNumber(reportSampleItem.getItemValue())) { judgeFormula = judgeFormula.replace(coed, reportSampleItem.getItemValue()); } else { judgeFormula = judgeFormula.replace(coed, "'" + reportSampleItem.getItemValue() + "'"); } } } } return judgeFormula; } /** * 替换值-合格函数 * * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ public static String replacePassFunction(String judgeFormula, List reportSampleItemList) { Matcher passMatcher = FunctionConfig.PATTEN_PASS.matcher(judgeFormula); List passFunctionList = new ArrayList(); addMatcherGroup(passFunctionList, passMatcher); if (CollectionUtil.isNotEmpty(passFunctionList)) { for (int i = 0; i < passFunctionList.size(); i++) { Matcher valueMatcher = FunctionConfig.PATTEN_VALUE.matcher(passFunctionList.get(i)); List valueList = new ArrayList(); addMatcherGroup(valueList, valueMatcher); // 合格函数里面只能有一个参数项 if (CollectionUtil.isNotEmpty(valueList) && valueList.size() == 1) { } else { throw new RuntimeException("公式不规范,合格函数里面只能有一个参数项:" + passFunctionList.get(i)); } } for (ReportSampleItem reportSampleItem : reportSampleItemList) { judgeFormula = replaceWildcardCharacter(judgeFormula, reportSampleItem.getItemCode()); // 根据 pass 空格 ( 空格 函数通配符 空格) 去匹配,防止有空格 String coedPatten = "\\b(pass)\\s*\\(\\s*(" + FunctionConfig.WILDCARD_CHARACTER + ")?\\s*\\)"; Matcher passCodeMatcher = Pattern.compile(coedPatten).matcher(judgeFormula); List passCodeList = new ArrayList(); addMatcherGroup(passCodeList, passCodeMatcher); if (CollectionUtil.isNotEmpty(passCodeList)) { if (reportSampleItem.getIsQualified() == null) { throw new RuntimeException("参与合格函数计算的检测项合格状态不能为空:" + reportSampleItem.getItemName()); } else { for (int i = 0; i < passCodeList.size(); i++) { judgeFormula = judgeFormula.replace(passCodeList.get(i), reportSampleItem.getIsQualified().toString()); } } } judgeFormula = reversalReplaceWildcardCharacter(judgeFormula, reportSampleItem.getItemCode()); } } // 这边再判断比对一下,预防不规范的写法 passMatcher = FunctionConfig.PATTEN_PASS.matcher(judgeFormula); passFunctionList = new ArrayList(); addMatcherGroup(passFunctionList, passMatcher); if (CollectionUtil.isNotEmpty(passFunctionList)) { throw new RuntimeException("公式存在无法处理的合格函数:" + judgeFormula); } return judgeFormula; } /** * 替换值-平均值函数 * * @param judgeFormula 需要替换的公式 * @param reportSampleItemList 检测项目值 * @return */ public static String replaceAvgFunction(String judgeFormula, List reportSampleItemList) { Matcher avgMatcher = FunctionConfig.PATTEN_AVG.matcher(judgeFormula); List avgFunctionList = new ArrayList(); addMatcherGroup(avgFunctionList, avgMatcher); if (CollectionUtil.isNotEmpty(avgFunctionList)) { for (int i = 0; i < avgFunctionList.size(); i++) { Matcher valueMatcher = FunctionConfig.PATTEN_VALUE.matcher(avgFunctionList.get(i)); List valueList = new ArrayList(); addMatcherGroup(valueList, valueMatcher); // 平均值函数里面至少有一个参数项 if (CollectionUtil.isEmpty(valueList)) { throw new RuntimeException("公式不规范,平均值函数里面至少有一个参数项:" + avgFunctionList.get(i)); } // 处理平均值函数,然后直接替换公式 List avgItemList = new ArrayList(); for (int j = 0; j < valueList.size(); j++) { for (ReportSampleItem reportSampleItem : reportSampleItemList) { String coed = "V[" + reportSampleItem.getItemCode() + "]"; if (valueList.get(j).contains(coed)) { // 平均值函数,几个参数有值,就按几个去计算 if (StringUtils.isNotBlank(reportSampleItem.getItemValue())) { avgItemList.add(reportSampleItem.getItemValue()); } break; } } } String replacement = ""; if (CollectionUtil.isNotEmpty(avgItemList)) { replacement = "(" + avgItemList.stream().collect(Collectors.joining("+")) + ")/" + avgItemList.size(); } else { replacement = "0"; } judgeFormula = judgeFormula.replace(avgFunctionList.get(i), replacement); } } // 这边再判断比对一下,预防不规范的写法 avgMatcher = FunctionConfig.PATTEN_AVG.matcher(judgeFormula); avgFunctionList = new ArrayList(); addMatcherGroup(avgFunctionList, avgMatcher); if (CollectionUtil.isNotEmpty(avgFunctionList)) { throw new RuntimeException("公式存在无法处理的平均值函数:" + judgeFormula); } return judgeFormula; } /** * 替换通配符 * * @param judgeFormula * @param itemCode * @return */ public static String replaceWildcardCharacter(String judgeFormula, String itemCode) { // V[检测项编号]先用通配符转一下,要不然自定义的检测项编号在下面正则匹配公式一直报错 return judgeFormula.replace("V[" + itemCode + "]", FunctionConfig.WILDCARD_CHARACTER); } /** * 替换通配符(反向) * * @param judgeFormula * @param itemCode * @return */ public static String reversalReplaceWildcardCharacter(String judgeFormula, String itemCode) { return judgeFormula.replace(FunctionConfig.WILDCARD_CHARACTER, "V[" + itemCode + "]"); } /** * 把正则匹配出来的字符串保存到list * * @param list * @param matcher */ public static void addMatcherGroup(List list, Matcher matcher) { while (matcher.find()) { list.add(matcher.group()); } } /** * 替换判定公式及计算公式中的参数code(重要前提:相同的原始code,不可能出现一个有线芯,一个没有线芯) * @param testStandardParamList 操作对象 * @param newCode 新的code * @param oldCode 旧的code */ public static void replaceFormulaParam(List testStandardParamList, String newCode, String oldCode) { for(TestStandardParam testStandardParam : testStandardParamList){ //如果公式字段中有值,则替换 if(StringUtils.isNotBlank(testStandardParam.getJudgeFormula())){ //判断公式 testStandardParam.setJudgeFormula(testStandardParam.getJudgeFormula().replace(oldCode,newCode)); } if(StringUtils.isNotBlank(testStandardParam.getValueFormula())){ //值计算公式 testStandardParam.setValueFormula(testStandardParam.getValueFormula().replace(oldCode,newCode)); } } } /** * 对数换底公式计算 * @param base 底数 * @param value 值 * @return */ public static double log(double base, double value) { return Math.log(value) / Math.log(base); } }