Forráskód Böngészése

计算公式解析校验结果

fengzhenzhong 1 hónapja
szülő
commit
2fcb1bcb69

+ 102 - 0
assistMg/src/main/java/com/hotent/util/CustomExpressionValidator.java

@@ -0,0 +1,102 @@
+package com.hotent.util;
+import java.util.Stack;
+import java.util.regex.Pattern;
+
+/**
+ * 检查四则运算表达式是否正确
+ */
+public class CustomExpressionValidator {
+
+    private static final Pattern VARIABLE_PATTERN = Pattern.compile("[a-zA-Z_.][a-zA-Z0-9_.]*");
+    private static final Pattern NUMBER_PATTERN = Pattern.compile("\\d+(\\.\\d+)?");
+
+    public static boolean isValidExpression(String expr) {
+        if (expr == null || expr.trim().isEmpty()) {
+            return false;
+        }
+
+        // 检查括号匹配
+        if (!checkParentheses(expr)) {
+            return false;
+        }
+
+        // 检查运算符使用
+        if (!checkOperators(expr)) {
+            return false;
+        }
+
+        // 检查变量命名
+        return checkVariables(expr);
+    }
+
+    private static boolean checkParentheses(String expr) {
+        Stack<Character> stack = new Stack<>();
+
+        for (char c : expr.toCharArray()) {
+            if (c == '(') {
+                stack.push(c);
+            } else if (c == ')') {
+                if (stack.isEmpty() || stack.pop() != '(') {
+                    return false;
+                }
+            }
+        }
+
+        return stack.isEmpty();
+    }
+
+    private static boolean checkOperators(String expr) {
+        String cleaned = expr.replaceAll("\\s+", "");
+
+        // 检查开头和结尾不能是运算符(除负号外)
+        if (isOperator(cleaned.charAt(0)) && cleaned.charAt(0) != '-') {
+            return false;
+        }
+        if (isOperator(cleaned.charAt(cleaned.length() - 1))) {
+            return false;
+        }
+
+        // 检查连续的运算符
+        for (int i = 0; i < cleaned.length() - 1; i++) {
+            char current = cleaned.charAt(i);
+            char next = cleaned.charAt(i + 1);
+
+            if (isOperator(current) && isOperator(next) && next != '-') {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean checkVariables(String expr) {
+        String[] tokens = expr.split("[+\\-*/()\\s]+");
+
+        for (String token : tokens) {
+            if (!token.isEmpty() && !NUMBER_PATTERN.matcher(token).matches() &&
+                    !VARIABLE_PATTERN.matcher(token).matches()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean isOperator(char c) {
+        return c == '+' || c == '-' || c == '*' || c == '/';
+    }
+
+    public static void main(String[] args) {
+        String[] testExpressions = {
+                "(taiyuan.c1+taiyuan.c2)*(c1/c2)+c1",
+                "c1++c2",           // 错误:连续运算符
+                "c1+",              // 错误:运算符在结尾
+                "(c1+c2",           // 错误:括号不匹配
+                "123c4 + 5"         // 错误:无效变量名
+        };
+
+        for (String expr : testExpressions) {
+            System.out.println(expr + " : " + isValidExpression(expr));
+        }
+    }
+}

+ 58 - 0
assistMg/src/main/java/com/hotent/util/ExpressionCalculator.java

@@ -0,0 +1,58 @@
+package com.hotent.util;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 提供表达式及参数结合计算结果
+ */
+public class ExpressionCalculator {
+
+    /**
+     * 计算包含变量的表达式
+     * @param expression 表达式,如 "(c1+c2)*(c1/c2)+c1"
+     * @param variables 变量映射表,如 {c1=10, c2=5}
+     * @return 计算结果
+     */
+    public static double calculateExpression(String expression, Map<String, Double> variables) {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("JavaScript");
+
+        try {
+            // 将变量放入引擎
+            for (Map.Entry<String, Double> entry : variables.entrySet()) {
+                engine.put(entry.getKey().replace(".","_"), entry.getValue());
+            }
+
+            // 计算表达式
+            Object result = engine.eval(expression.replace(".","_"));
+
+            if (result instanceof Number) {
+                return ((Number) result).doubleValue();
+            } else {
+                throw new RuntimeException("表达式计算结果不是数字: " + result);
+            }
+        } catch (ScriptException e) {
+            throw new RuntimeException("表达式计算错误: " + e.getMessage(), e);
+        }
+    }
+
+    public static void main(String[] args) {
+        String expression = "(taiyuan.c1+taiyuan.c2)*(c1/c2)+c1";
+
+        // 方式1:手动指定变量值
+        Map<String, Double> variables1 = new HashMap<>();
+        variables1.put("c1", 10.0);
+        variables1.put("c2", 5.0);
+        variables1.put("taiyuan.c1",1.0);
+        variables1.put("taiyuan.c2",2.0);
+
+        double result1 = calculateExpression(expression, variables1);
+        System.out.println("表达式: " + expression);
+        System.out.println("结果: " + result1);
+        System.out.println();
+    }
+}

+ 97 - 0
assistMg/src/main/java/com/hotent/util/VariableParser.java

@@ -0,0 +1,97 @@
+package com.hotent.util;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 从表达式提取参数变量
+ */
+public class VariableParser {
+
+    /**
+     * 从四则运算表达式中提取所有变量
+     * @param expression 四则运算表达式
+     * @return 变量名的Set集合
+     */
+    public static Set<String> extractVariables(String expression) {
+        Set<String> variables = new HashSet<>();
+
+        // 正则表达式:匹配变量名(字母或下划线开头,后跟字母、数字或下划线)
+        Pattern pattern = Pattern.compile("[a-zA-Z_.][a-zA-Z0-9_.]*");
+        Matcher matcher = pattern.matcher(expression);
+
+        // JavaScript/数学函数和常量黑名单
+        Set<String> blacklist = new HashSet<>(Arrays.asList(
+                "Math", "math",
+                "sin", "cos", "tan", "cot", "sec", "csc",
+                "asin", "acos", "atan", "acot",
+                "sinh", "cosh", "tanh",
+                "log", "ln", "lg", "exp",
+                "sqrt", "cbrt", "abs",
+                "PI", "E", "pi", "e",
+                "min", "max", "pow", "random"
+        ));
+
+        while (matcher.find()) {
+            String potentialVar = matcher.group();
+
+            // 检查是否是黑名单中的数学函数或常量
+            if (!blacklist.contains(potentialVar)) {
+                // 检查是否全是数字(虽然正则已经排除了以数字开头的情况,但确保安全)
+                if (!potentialVar.matches("\\d+")) {
+                    variables.add(potentialVar);
+                }
+            }
+        }
+
+        return variables;
+    }
+
+    /**
+     * 提取变量并统计出现次数
+     */
+    public static Map<String, Integer> extractVariablesWithCount(String expression) {
+        Map<String, Integer> variableCount = new HashMap<>();
+
+        // 数学函数和常量黑名单
+        Set<String> blacklist = new HashSet<>(Arrays.asList(
+                "Math", "sin", "cos", "tan", "log", "sqrt", "PI", "E"
+        ));
+
+        Pattern pattern = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*");
+        Matcher matcher = pattern.matcher(expression);
+
+        while (matcher.find()) {
+            String potentialVar = matcher.group();
+
+            if (!blacklist.contains(potentialVar) && !potentialVar.matches("\\d+")) {
+                variableCount.put(potentialVar, variableCount.getOrDefault(potentialVar, 0) + 1);
+            }
+        }
+
+        return variableCount;
+    }
+
+    public static void main(String[] args) {
+        String[] testExpressions = {
+                "(taiyuan.c1+taiyuan.c2)*(c1/c2)+c1",
+                "a + b * c - d / e",
+                "sin(x) + cos(y) + log(z)",
+                "width * height + depth",
+                "2 * PI * radius",
+                "temp1 + temp2 - temp3 * temp4",
+                "var_1 + var_2 * var_test"
+        };
+
+        for (String expr : testExpressions) {
+            Set<String> variables = extractVariables(expr);
+            Map<String, Integer> variableCount = extractVariablesWithCount(expr);
+
+            System.out.println("表达式: " + expr);
+            System.out.println("提取的变量: " + variables);
+            System.out.println("变量出现次数: " + variableCount);
+            System.out.println();
+        }
+    }
+}