JAVA计算字符串数学表达式及SQL占位符处理

JAVA计算字符串数学表达式

作用:
给定一个字符串描述的算术表达式,计算出结果值。
输入字符串长度不超过 100 ,合法的字符包括 ”+, -, *, /, (, )” , ”0-9” 。

例如:

入参:"(5-1)*3" :输出:12

入参:"16/2" :输出:8

/**
     ** 计算数学表达式
     * @param expressions 表达式
     * @return int 计算结果
     * @author yinqi
     * @create 2024/3/21 18:27
     **/
    public static int calculateMathExpressions(String expressions) {
        Stack<Integer> stack_nums = new Stack<>();
        Stack<Character> stack_symbol = new Stack<>();
        Map<Character, Integer> map = new HashMap<>();
        map.put('+', 1);
        map.put('-', 1);
        map.put('*', 2);
        map.put('/', 2);

        if (expressions.charAt(0) == '-') {//第一个数为负数
            expressions = "0" + expressions;
        }
        expressions = expressions.replace("(-", "(0-");//其他位置负数处理
        for (int i = 0; i < expressions.length(); i++) {
            char ch = expressions.charAt(i);
            if (ch == ' ') continue;
            if (ch == '(') {
                stack_symbol.push(ch);
                continue;
            }
            if (ch == ')') {
                //括号结束计算一次
                stack_nums.push(calculate(stack_nums, stack_symbol));
                if (!stack_symbol.isEmpty() && stack_symbol.peek() == '(') {
                    //当前计算是括号内最后一次运算,弹出左括号
                    stack_symbol.pop();
                }
                continue;
            }
            if (map.containsKey(ch)) {
                // 栈内至少有1个运算符且栈顶不是左括号,并且栈内运算符优先级大于等于当前运算符号优先级,执行一次计算,
                // 即先消费已入栈的高优先级运算符
                while (!stack_symbol.isEmpty() && stack_symbol.peek() != '(' && map.get(stack_symbol.peek()) >= map.get(ch)) {
                    stack_nums.push(calculate(stack_nums, stack_symbol));
                }
                stack_symbol.push(ch);
            } else {
                int num = 0;
                int j = i;//循环读取十进制整数
                while (j < expressions.length() && Character.isDigit(expressions.charAt(j))) {
                    num = num * 10 + expressions.charAt(j) - '0';
                    j++;
                }
                stack_nums.push(num);
                i = j - 1;
            }
        }
        // 循环结束还有未算尽的式子,优先级低
        while (!stack_symbol.isEmpty()) {
            stack_nums.push(calculate(stack_nums, stack_symbol));
            if (!stack_symbol.isEmpty() && stack_symbol.peek() == '(') {
                stack_symbol.pop();
            }
        }
        return stack_nums.pop();
    }

    /**
     * 执行运算
     * @param stack_nums 操作数栈
     * @param stack_symbol 运算符栈
     * @return
     */
    public static int calculate(Stack<Integer> stack_nums, Stack<Character> stack_symbol) {
        int res = 0;
        int opt_nums2 = stack_nums.pop();
        int opt_nums1 = stack_nums.pop();
        char symbol = stack_symbol.pop();
        switch (symbol) {
            case '+': {
                res = opt_nums1 + opt_nums2;
                break;
            }
            case '-': {
                res = opt_nums1 - opt_nums2;
                break;
            }
            case '*': {
                res = opt_nums1 * opt_nums2;
                break;
            }
            case '/': {
                res = opt_nums1 / opt_nums2;
                break;
            }
        }
        return res;
    }

java处理SQL中的占位符和表达式

作用:

传入初始的带占位符的sql语句和参数,替换占位符并计算sql中的表达式后返回最终可执行的sql。

表达式:#{}

字符串占位符:'${}'

整数占位符:${}

当前页:${currentPage}

每页显示记录数:${pageSize}

mySql分页:limit #{(${currentPage} - 1) * ${pageSize}}, ${pageSize}

例如:

输入:
String sql2 = " select * from sys_user where status = '${status}'
 and sort < #{${currentPage}*${pageSize}} 
 and sort > #{ (${currentPage} - 1) * ${pageSize} } ";
Map<String, Object> params = new HashMap<>();
        params.put("status", 0);
        params.put("login_name", "%a%");
        params.put("currentPage", 5);
        params.put("pageSize", 10);
输出:
select * from sys_user where status = '0' and sort < 50 and sort > 40

代码:

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ScreenConfigUtil {
    /**
     ** 替换占位符
     * @param sql
     * @param params
     * @return java.lang.String
     * @author yinqi
     * @create 2024/3/21 18:42
     **/
    public static String replaceSqlPlaceholders(String sql, Map<String, Object> params) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
        Matcher matcher = pattern.matcher(sql);
        StringBuffer sb = new StringBuffer();

        while (matcher.find()) {
            String placeholder = matcher.group(1);
            Object value = params.get(placeholder);
            String replacement = value != null ? value.toString() : "";
            matcher.appendReplacement(sb, replacement);
        }

        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     ** 提取#{}里面的内容
     * @param input
     * @return java.lang.String
     * @author yinqi
     * @create 2024/3/21 18:34
     **/
    public static List<String> extractValues(String input) {
        List<String> values = new ArrayList<>();
        Pattern pattern = Pattern.compile("#\\{(.*?)\\}");
        Matcher matcher = pattern.matcher(input);
        while (matcher.find()) {
            values.add(matcher.group(1));
        }
        return values;
    }


    /**
     ** 使用map中的value替换str字符串中的key
     * @param str
     * @param expressValMap
     * @return java.lang.String
     * @author yinqi
     * @create 2024/3/21 18:38
     **/
    public static String replaceValue(String str, HashMap<String, String> expressValMap) {
        for (String key : expressValMap.keySet()){
            String val = expressValMap.get(key);
            str = str.replace(key, val);
        }
        return str;
    }

    /**
     ** 计算数学表达式
     * @param expressions 表达式
     * @return int 计算结果
     * @author yinqi
     * @create 2024/3/21 18:27
     **/
    public static int calculateMathExpressions(String expressions) {
        Stack<Integer> stack_nums = new Stack<>();
        Stack<Character> stack_symbol = new Stack<>();
        Map<Character, Integer> map = new HashMap<>();
        map.put('+', 1);
        map.put('-', 1);
        map.put('*', 2);
        map.put('/', 2);

        if (expressions.charAt(0) == '-') {//第一个数为负数
            expressions = "0" + expressions;
        }
        expressions = expressions.replace("(-", "(0-");//其他位置负数处理
        for (int i = 0; i < expressions.length(); i++) {
            char ch = expressions.charAt(i);
            if (ch == ' ') continue;
            if (ch == '(') {
                stack_symbol.push(ch);
                continue;
            }
            if (ch == ')') {
                //括号结束计算一次
                stack_nums.push(calculate(stack_nums, stack_symbol));
                if (!stack_symbol.isEmpty() && stack_symbol.peek() == '(') {
                    //当前计算是括号内最后一次运算,弹出左括号
                    stack_symbol.pop();
                }
                continue;
            }
            if (map.containsKey(ch)) {
                // 栈内至少有1个运算符且栈顶不是左括号,并且栈内运算符优先级大于等于当前运算符号优先级,执行一次计算,
                // 即先消费已入栈的高优先级运算符
                while (!stack_symbol.isEmpty() && stack_symbol.peek() != '(' && map.get(stack_symbol.peek()) >= map.get(ch)) {
                    stack_nums.push(calculate(stack_nums, stack_symbol));
                }
                stack_symbol.push(ch);
            } else {
                int num = 0;
                int j = i;//循环读取十进制整数
                while (j < expressions.length() && Character.isDigit(expressions.charAt(j))) {
                    num = num * 10 + expressions.charAt(j) - '0';
                    j++;
                }
                stack_nums.push(num);
                i = j - 1;
            }
        }
        // 循环结束还有未算尽的式子,优先级低
        while (!stack_symbol.isEmpty()) {
            stack_nums.push(calculate(stack_nums, stack_symbol));
            if (!stack_symbol.isEmpty() && stack_symbol.peek() == '(') {
                stack_symbol.pop();
            }
        }
        return stack_nums.pop();
    }

    /**
     * 执行运算
     * @param stack_nums 操作数栈
     * @param stack_symbol 运算符栈
     * @return
     */
    public static int calculate(Stack<Integer> stack_nums, Stack<Character> stack_symbol) {
        int res = 0;
        int opt_nums2 = stack_nums.pop();
        int opt_nums1 = stack_nums.pop();
        char symbol = stack_symbol.pop();
        switch (symbol) {
            case '+': {
                res = opt_nums1 + opt_nums2;
                break;
            }
            case '-': {
                res = opt_nums1 - opt_nums2;
                break;
            }
            case '*': {
                res = opt_nums1 * opt_nums2;
                break;
            }
            case '/': {
                res = opt_nums1 / opt_nums2;
                break;
            }
        }
        return res;
    }

    /**
     ** 传入初始的sql,处理后返回最终可执行的sql
     * @param sql
     * @param params
     * @return java.lang.String
     * @author yinqi
     * @create 2024/3/21 18:48
     **/
    public static String getSql(String sql, Map<String, Object> params) {
        // 替换占位符
        String result = replaceSqlPlaceholders(sql, params);

        // 提取#{}里面的内容
        List<String> expressList = extractValues(result);

        if (CollectionUtil.isNotEmpty(expressList)){
            // 存放键值对 --> 表达式:表达式计算结果
            HashMap<String, String> expressValMap = new HashMap<>();
            // 计算表达式的值
            for(String express : expressList){
                int expressResult = calculateMathExpressions(express);
                expressValMap.put("#{" + express + "}", String.valueOf(expressResult));
            }

            // 使用新值替换#{}
            result = replaceValue(result, expressValMap);
        }

        return result;
    }

    public static void main(String[] args) {
        String sql1 = "select * from sdp_sys_user where status = '${status}' and login_name like '${login_name}' limit #{ (${currentPage} - 1) * ${pageSize} }, ${pageSize}";
        String sql2 = " select * from sdp_sys_user where status = '${status}' and sort < #{${currentPage}*${pageSize}} and sort > #{ (${currentPage} - 1) * ${pageSize} } ";
        Map<String, Object> params = new HashMap<>();
        params.put("status", 0);
        params.put("login_name", "%a%");
        params.put("currentPage", 5);
        params.put("pageSize", 10);
        String resultSql1 = getSql(sql1, params);
        String resultSql2 = getSql(sql2, params);

        System.out.println("原来的sql1:"+sql1);
        System.out.println("最终的sql1:"+resultSql1);
        System.out.println("------------------------------------------------------------------------------------------");
        System.out.println("原来的sql2:"+sql2);
        System.out.println("最终的sql2:"+resultSql2);
    }
}

VUE中实现codemirror组件中失去焦点时,向codemirror中鼠标所在位置插入指定字符串

data中定义一个变量来保存鼠标焦点所在的位置。然后,在失去焦点时,调用Codemirror实例的getCursor()方法获取鼠标焦点的位置。最后,调用replaceRange()方法插入指定的字符串到鼠标焦点位置。

cmOptions需要根据实际需求进行配置。

<template>
  <codemirror
    ref="mycode"
    :value="newFormData.sql"
    :options="cmOptions"
    @blur="codemirrorBlur()"
  />
</template>

<script>
import 'codemirror/addon/display/autoRefresh.js';
export default {
  data() {
    return {
      cursor: null, // 保存鼠标焦点位置
      newFormData: {
        sql: ''
      },
      cmOptions: {
        // codemirror的配置选项
		tabSize: 4,
        mode: "text/x-mariadb", //选择对应代码编辑器的语言
        theme: "midnight", //主题
        lineNumbers: true,
        line: true,
        autoRefresh: true
      }

    };
  },
  methods: {
    codemirrorBlur() {
      // 失去焦点时的处理逻辑
      this.cursor = this.$refs.mycode.codemirror.getCursor(); // 获取鼠标焦点位置
      this.$refs.mycode.codemirror.replaceRange('自动插入的字符串', this.cursor); // 插入指定字符串到鼠标焦点位置
    }
  }
};
</script>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值