后缀表达式解析

工具类

package com.hare.zebra.util;

import cn.hutool.core.util.NumberUtil;
import com.basics.exception.BusinessException;
import com.hare.zebra.enums.OperatorEnums;
import lombok.extern.slf4j.Slf4j;

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

/**
 * [Description]: 表达式生成与执行工具类
 */
@Slf4j
public class EpressionUtil {
    private final static String LEFT_BRACKET = "(";
    private final static String RIGHT_BRACKET = ")";
    private final static String LEFT_FRENCH_QUOTES = "{";
    private final static String RIGHT_FRENCH_QUOTES = "}";
    /**
     * 判断是否包含{n}
     */
    private final static Pattern PATTERN = Pattern.compile("\\{[^}]+}");

    public static void main(String[] args) {
        //需要解析的表达式   
        String parameter = "(6>11)&(12>5)";
        log.info("需要解析的表达式:{}", parameter);
        //将表达式转为list
        List<String> list = expressionToList(parameter);
        log.info("将表达式转为list:{}", list);
        //生成后缀表达式
        List<String> expression = parseToSuffixExpression(list);
        log.info("生成后缀表达式:{}", expression);
        //解析结果
        int calculateFlag = calculate(expression);
        log.info("解析结果:{}", calculateFlag);
    }

    /**
     * 生成后缀表达式
     *
     * @param expressionList 前缀表达式
     **/
    public static List<String> parseToSuffixExpression(List<String> expressionList) {
        //创建一个栈用于保存操作符
        Stack<String> opStack = new Stack<>();
        //创建一个list用于保存后缀表达式
        List<String> suffixList = new ArrayList<>();
        for (String item : expressionList) {
            //得到数或操作符
            if (isOperator(item)) {
                //是操作符 判断操作符栈是否为空
                if (opStack.isEmpty() || LEFT_BRACKET.equals(opStack.peek()) || priority(item) > priority(opStack.peek())) {
                    //为空或者栈顶元素为左括号或者当前操作符大于栈顶操作符直接压栈
                    opStack.push(item);
                } else {
                    //否则将栈中元素出栈如队,直到遇到大于当前操作符或者遇到左括号时
                    while (!opStack.isEmpty() && !LEFT_BRACKET.equals(opStack.peek())) {
                        if (priority(item) <= priority(opStack.peek())) {
                            suffixList.add(opStack.pop());
                        }
                    }
                    //当前操作符压栈
                    opStack.push(item);
                }
            } else if (NumberUtil.isNumber(item) || PATTERN.matcher(item).find()) {
                //是数字则直接入队
                suffixList.add(item);
            } else if (LEFT_BRACKET.equals(item)) {
                //是左括号,压栈
                opStack.push(item);
            } else if (RIGHT_BRACKET.equals(item)) {
                //是右括号 ,将栈中元素弹出入队,直到遇到左括号,左括号出栈,但不入队
                while (!opStack.isEmpty()) {
                    if (LEFT_BRACKET.equals(opStack.peek())) {
                        opStack.pop();
                        break;
                    } else {
                        suffixList.add(opStack.pop());
                    }
                }
            } else {
                throw new RuntimeException("有非法字符!");
            }
        }
        //循环完毕,如果操作符栈中元素不为空,将栈中元素出栈入队
        while (!opStack.isEmpty()) {
            suffixList.add(opStack.pop());
        }
        return suffixList;
    }

    /**
     * 判断字符串是否为操作符
     *
     * @param op
     * @return
     */
    private static boolean isOperator(String op) {
        Optional<OperatorEnums> first = Arrays.asList(OperatorEnums.values()).stream().filter(e -> e.getName().equals(op)).findFirst();
        return first.isPresent();
    }


    /**
     * 获取操作符的优先级
     *
     * @param op
     * @return
     */
    private static int priority(String op) {
        OperatorEnums operatorEnums = Arrays.asList(OperatorEnums.values()).stream().filter(e -> e.getName().equals(op)).findFirst().orElseThrow(() -> new BusinessException("符号错误!"));
        return operatorEnums.getPriority();
    }


    /**
     * 将表达式转为list
     *
     * @param expression 条件表达式
     */
    public static List<String> expressionToList(String expression) {
        int index = 0;
        List<String> list = new ArrayList<>();
        do {
            String c = String.valueOf(expression.charAt(index));
            if (!NumberUtil.isNumber(c)) {
                //是操作符,直接添加至list中
                //这里需要判断是否为{
                if (c.equals(LEFT_FRENCH_QUOTES)) {
                    String str = "";
                    while (index < expression.length()) {
                        str += expression.charAt(index);
                        if (String.valueOf(expression.charAt(index)).equals(RIGHT_FRENCH_QUOTES)) {
                            c = str;
                            break;
                        }
                        index++;
                    }
                }
                list.add(c);
                index++;
            } else {
                //是数字,判断多位数的情况
                String str = "";
                while (index < expression.length() && NumberUtil.isNumber(String.valueOf(expression.charAt(index)))) {
                    str += expression.charAt(index);
                    index++;
                }
                list.add(str);
            }
        } while (index < expression.length());
        return list;
    }

    /**
     * 根据后缀表达式list计算结果
     *
     * @param list 后缀表达式
     * @return
     */
    public static int calculate(List<String> list) {
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < list.size(); i++) {
            String item = list.get(i);
            if (NumberUtil.isNumber(item)) {
                //是数字
                int value = Integer.parseInt(item);
                stack.push(value);
            } else {
                //是操作符,取出栈顶两个元素

                int num2 = stack.pop();
                int num1 = stack.pop();
                //获取操作符的计算方式
                OperatorEnums operatorEnums = Arrays.asList(OperatorEnums.values()).stream()
                        .filter(e -> e.getName().equals(item)).findFirst().orElseThrow(() -> new BusinessException("操作符未知!"));
                int res = operatorEnums.getExecuteFunction().apply(new Integer[]{num1, num2});
                stack.push(res);
            }
        }
        return stack.pop();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值