Browse Source

设计实现区间公式内的函数求值

‘xugp 2 years atrás
parent
commit
58649bd446

+ 58 - 0
ims-service/ims-eval/src/main/java/com/ims/eval/expression/AlarmExpression.java

@@ -0,0 +1,58 @@
+package com.ims.eval.expression;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class AlarmExpression {
+
+    private String funCode;
+
+    private String funType;
+
+    private String originalExpression;
+
+    private String expression;
+
+    private List<String> varList;
+
+    private List<AlarmExpression> children;
+
+    private AlarmExpression parent;
+
+    private String ruleId;
+
+    private ArrayList<String> funParams;
+
+
+    public ArrayList<String> getAllUniformCodes() {
+        ArrayList<String> result = new ArrayList<>();
+        if (varList != null && varList.size() > 0) {
+            for (String var : varList) {
+                if (var.startsWith(Analyzer.FUNCODE) == false)
+                    result.add(var);
+            }
+        }
+
+        if (children != null && children.size() > 0) {
+            for (AlarmExpression subExp : children) {
+                ArrayList<String> r2 = subExp.getAllUniformCodes();
+                if (r2.size() > 0) {
+                    for (String svar : r2) {
+                        if (svar.startsWith(Analyzer.FUNCODE) == false)
+                            result.add(svar);
+                    }
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return expression;
+    }
+}

+ 1 - 1
ims-service/ims-eval/src/main/java/com/ims/eval/schedule/AlarmScript.java

@@ -1,4 +1,4 @@
-package com.ims.eval.schedule;
+package com.ims.eval.expression;
 
 import groovy.lang.Script;
 

+ 231 - 0
ims-service/ims-eval/src/main/java/com/ims/eval/expression/Analyzer.java

@@ -0,0 +1,231 @@
+package com.ims.eval.expression;
+
+
+
+import com.ims.eval.util.MathCalculatorUtil;
+
+import java.util.*;
+
+public class Analyzer {
+
+    public static final String FUNCODE = "Function";
+
+    //自定义函数名集合
+    public static final HashSet<String> CUSTOM_FUNS = new HashSet<String>() {{
+        add("max");
+        add("min");
+        add("abs");
+        add("acos");
+        add("asin");
+        add("atan");
+        add("ceil");
+		add("cos");
+		add("exp");
+		add("floor");
+		add("log");
+		add("pow");
+		add("round");
+		add("sin");
+		add("sqrt");
+		add("tan");
+    }};
+
+    public static AlarmExpression getAlarmExpression(String exp) {
+        ArrayList<Token> tokens = getTokens(exp);
+        return createAlarmExpression(tokens);
+    }
+
+    public static ArrayList<Token> getTokens(String exp) {
+        ArrayList<Token> tokens = new ArrayList<>();
+        int expIndex = 0;
+        int tokenIndex = 0;
+        while (expIndex < exp.length()) {
+            char currentChar = exp.charAt(expIndex);
+            //如果当前字符是一个分隔符,则认为这是一个分隔符标记
+            //给当前标记和标记类型赋值,并将指针后移
+            if (isDelim(currentChar)) {
+                Token token = new Token();
+                token.setValue(currentChar + "");
+                if (currentChar == '(') {
+                    token.setTokenType(TokenType.PARENTHESISL);
+                    //识别出函数名
+                    if (tokens.size() > 0) {
+                        Token preToken = tokens.get(tokens.size() - 1);
+                        if (preToken.getTokenType() == TokenType.VARIABE &&
+                                CUSTOM_FUNS.contains(preToken.getValue())) {
+                            preToken.setTokenType(TokenType.CUSTOMFUN);
+                        } else {
+                            preToken.setTokenType(TokenType.SYSFUN);
+                        }
+                    }
+                } else if (currentChar == ')')
+                    token.setTokenType(TokenType.PARENTHESISR);
+                else
+                    token.setTokenType(TokenType.OTHER);
+
+                if (currentChar != ' ')
+                    tokens.add(token);
+                tokenIndex = 0;
+            } else if (isVariable(currentChar)) {
+                if (tokenIndex == 0) {
+                    Token token = new Token();
+                    token.setValue(currentChar + "");
+                    if (currentChar >= '0' && currentChar <= '9')
+                        token.setTokenType(TokenType.CONST);
+                    else
+                        token.setTokenType(TokenType.VARIABE);
+                    tokens.add(token);
+                } else {
+                    Token token = tokens.get(tokens.size() - 1);
+                    token.setValue(token.getValue() + currentChar);
+                }
+                tokenIndex++;
+            } else {
+                //其他字符,忽略
+            }
+            expIndex++;
+        }
+
+        return tokens;
+    }
+
+    //判断一个字符是否为分隔符
+    public static boolean isDelim(char c) {
+        if (("+-*/><=&|! ,()".indexOf(c) != -1))
+            return true;
+        return false;
+    }
+
+    //判断一个字符是否为字母数字或小数点
+    public static boolean isVariable(char c) {
+        if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '.' || c == '_')
+            return true;
+
+        return false;
+    }
+
+    public static AlarmExpression createAlarmExpression(ArrayList<Token> tokens) {
+        AlarmExpression alarmExpression = new AlarmExpression();
+        alarmExpression.setFunCode("ROOT");
+
+        List<AlarmExpression> subFun = new ArrayList<>();
+        int funCnt = 0;
+        List<String> varList = new ArrayList<>();
+        StringBuilder sbExp = new StringBuilder();
+
+        int tokenIndex = 0;
+        while (tokenIndex < tokens.size()) {
+            Token token = tokens.get(tokenIndex);
+            if (token.getTokenType() == TokenType.VARIABE) {
+                if (varList.contains(token.getValue()) == false)
+                    varList.add(token.getValue());
+                sbExp.append(token.getValue());
+            } else if (token.getTokenType() == TokenType.CUSTOMFUN) {
+                ArrayList<Token> subTokens = getFunTokens(tokens, tokenIndex);
+                AlarmExpression subExp = createCustomFunExpression(subTokens);
+                String subFunCode = FUNCODE + funCnt++;
+                subExp.setFunCode(subFunCode);
+                subExp.setParent(alarmExpression);
+                subFun.add(subExp);
+                varList.add(subFunCode);
+                sbExp.append(subFunCode);
+
+                tokenIndex += subTokens.size();
+                continue;
+            } else {
+                sbExp.append(token.getValue());
+            }
+
+            tokenIndex++;
+        }
+
+        alarmExpression.setVarList(varList);
+        alarmExpression.setExpression(sbExp.toString());
+        alarmExpression.setChildren(subFun);
+
+        return alarmExpression;
+    }
+
+    private static AlarmExpression createCustomFunExpression(ArrayList<Token> tokens) {
+        AlarmExpression alarmExpression = new AlarmExpression();
+
+        List<AlarmExpression> subExps = new ArrayList<>();
+        int funCnt = 0;
+        List<String> varList = new ArrayList<>();
+        List<String> paramList = new ArrayList<>();
+        StringBuilder sbExp = new StringBuilder();
+        alarmExpression.setFunType(tokens.get(0).getValue());
+        sbExp.append(tokens.get(0).getValue());
+
+        int tokenIndex = 1;
+        while (tokenIndex < tokens.size()) {
+            Token token = tokens.get(tokenIndex);
+            if (token.getTokenType() == TokenType.VARIABE) {
+                if (varList.contains(token.getValue()) == false)
+                    varList.add(token.getValue());
+                sbExp.append(token.getValue());
+            } else if (token.getTokenType() == TokenType.CUSTOMFUN) {
+                ArrayList<Token> subTokens = getFunTokens(tokens, tokenIndex);
+                AlarmExpression subExp = createCustomFunExpression(subTokens);
+                subExp.setParent(alarmExpression);
+                String subFunCode = FUNCODE + funCnt++;
+                subExp.setFunCode(subFunCode);
+                subExps.add(subExp);
+                varList.add(subFunCode);
+                sbExp.append(subFunCode);
+                tokenIndex += subTokens.size();
+                continue;
+            } else {
+                sbExp.append(token.getValue());
+            }
+
+            tokenIndex++;
+        }
+
+        alarmExpression.setVarList(varList);
+        alarmExpression.setExpression(sbExp.toString());
+        alarmExpression.setChildren(subExps);
+
+        return alarmExpression;
+    }
+
+    private static ArrayList<Token> getFunTokens(ArrayList<Token> tokens, int startIndex) {
+        ArrayList<Token> result = new ArrayList<>();
+        int cntL = 0;
+        int cntR = 0;
+        while (startIndex < tokens.size()) {
+            Token token = tokens.get(startIndex);
+            result.add(token);
+            if (token.getTokenType() == TokenType.PARENTHESISL) {
+                cntL++;
+            } else if (token.getTokenType() == TokenType.PARENTHESISR) {
+                if (++cntR == cntL) {
+                    break;
+                }
+            }
+            startIndex++;
+        }
+
+        return result;
+    }
+
+
+/*    public static void main(String[] args) {
+        String exp = "max(1,3)>0 && min(2,4)<0";
+
+
+        ArrayList<Token> tokens = getTokens(exp);
+        for (Token token : tokens) {
+            System.out.println(token.getValue() + "----" + token.getTokenType());
+        }
+
+        AlarmExpression alarmExpression = createAlarmExpression(tokens);
+		List<AlarmExpression> children = alarmExpression.getChildren();
+		for (AlarmExpression alarmExpression1 : children){
+			String calculator = MathCalculatorUtil.calculator(alarmExpression1.getExpression());
+			alarmExpression.setExpression(alarmExpression.getExpression().replaceAll(alarmExpression1.getFunCode(), calculator));
+		}
+		System.out.println(alarmExpression.getFunType());
+
+    }*/
+}

+ 2 - 1
ims-service/ims-eval/src/main/java/com/ims/eval/schedule/ScriptShell.java

@@ -1,5 +1,6 @@
-package com.ims.eval.schedule;
+package com.ims.eval.expression;
 
+import com.ims.eval.expression.AlarmScript;
 import groovy.lang.Binding;
 import groovy.lang.GroovyShell;
 import groovy.lang.Script;

+ 17 - 0
ims-service/ims-eval/src/main/java/com/ims/eval/expression/Token.java

@@ -0,0 +1,17 @@
+package com.ims.eval.expression;
+
+import lombok.Data;
+
+/**
+ * @author :xugp
+ * @date :Created in 2023/3/21 9:49
+ * @description:拆分表达式存储
+ * @modified By:
+ * @version: $
+ */
+
+@Data
+public class Token {
+    private String value;
+    private TokenType tokenType;
+}

+ 20 - 0
ims-service/ims-eval/src/main/java/com/ims/eval/expression/TokenType.java

@@ -0,0 +1,20 @@
+package com.ims.eval.expression;
+
+
+/**
+ * @author :xugp
+ * @date :Created in 2023/3/21 9:49
+ * @description:表达式包含元素枚举
+ * @modified By:
+ * @version: $
+ */
+public enum TokenType {
+    EMPTY,  //空,未赋值
+    VARIABE, //变量
+    CONST,  //常量
+    CUSTOMFUN, //自定义函数
+    SYSFUN, //标准库函数
+    PARENTHESISL, //圆括号左边
+    PARENTHESISR,  //圆括号右边
+    OTHER //其他符号,包括运算符,逗号等
+}

+ 20 - 8
ims-service/ims-eval/src/main/java/com/ims/eval/schedule/ScoreCalculationSchedule.java

@@ -4,19 +4,18 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.ims.common.utils.StringUtils;
 import com.ims.eval.dao.*;
 import com.ims.eval.entity.*;
+import com.ims.eval.expression.AlarmExpression;
+import com.ims.eval.expression.Analyzer;
+import com.ims.eval.expression.ScriptShell;
+import com.ims.eval.expression.Token;
 import com.ims.eval.service.IEvaluationScoreCountService;
-import com.ims.eval.service.impl.EvaluatioinScoreCountServiceImpl;
 import com.ims.eval.util.MathCalculatorUtil;
-import lombok.Builder;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.stereotype.Component;
 
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -139,13 +138,26 @@ public class ScoreCalculationSchedule {
 
 	/*
 	*  判断是否在这个区间
-	*
 	* */
 	public Boolean handle(String range) {
 
 		Map<String,Object> map = new HashMap<>();
-		Boolean o = (Boolean)ScriptShell.parseExpr(range, map);
+
+		//将区间表达式拆分
+		ArrayList<Token> tokens = Analyzer.getTokens(range);
+		//使用不同编码代替函数
+		AlarmExpression alarmExpression = Analyzer.createAlarmExpression(tokens);
+		List<AlarmExpression> children = alarmExpression.getChildren();
+		for (AlarmExpression alarmExpression1 : children){
+			String calculator = MathCalculatorUtil.calculator(alarmExpression1.getExpression());
+			alarmExpression.setExpression(alarmExpression.getExpression().replaceAll(alarmExpression1.getFunCode(), calculator));
+		}
+
+		//判断表达式返回结果
+		Boolean o = (Boolean) ScriptShell.parseExpr(alarmExpression.getExpression(), map);
+
 		return o;
 
 	}
+
 }