Java栈实现简单的计算器

 
/** * java栈实现简单的计算器 * 计算表达式的值 * 实现+、-、/、*、%、(、) * #表示表达式的开始与结束 */
import java.util.Stack;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class Calculator {
    private Stack<String> operation = new Stack<String>();// 存放运算符的栈
    private Stack<Double> number = new Stack<Double>();// 存放数字的栈
    public static final String ERROR = "ERROR";
 
    public String calculator(String expression) {
        operation.clear();
        number.clear();
        String[] str = getCharacters(expression);
        for (int i = 0; i < str.length; ++i) {
            if (i == 0) {
                if (str[i].equals(ERROR)) /* 表达式错误 */
                    return ERROR;
                operation.add(str[i]); /* 第一个"#"入栈 */
            } else {
                if (isNumber(str[i])) {// 如果是数字
                    number.add(Double.parseDouble(str[i])); // 入数据栈
                }
                /* * 运算符入栈规则: * 1."("直接入栈,不用判断优先级 * 2.当前扫描的运算符的优先级高于运算符栈顶的运算符优先级,将当前运算符入栈 */
                if (isOperation(str[i])) {
                    // 入操作符栈
                    if ("(".equals(str[i])) {
                        // 左括号直接入栈
                        operation.add(str[i]);
                    } else {
                        if (!operation.isEmpty()) {
                            if (operation.isEmpty()) {
                                number.clear();
                                return ERROR;
                            }
                            String topElement = operation.peek(); // 运算符栈顶元素
                            int topElementLevel = getLevel(topElement); // 运算符栈顶元素优先级
                            int curElementLevel = getLevel(str[i]); // 当前扫描的运算符的优先级
                            /* * 当前扫描的运算符的优先级小于运算符栈顶的运算符优先级: * 则取出操作数栈顶前2个数和运算符栈顶符号进行运算 */
                            while (curElementLevel < topElementLevel) {
                                // 运算前判断
                                if (operation.size() < 2 || number.size() < 2) {
                                    operation.clear();
                                    number.clear();
                                    return ERROR;
                                }
                                // 计算并将结果入栈
                                number.add(calc(number.pop(), number.pop(), operation.pop()));
                                // 运算完之后重新获取运算符栈顶元素
                                topElement = operation.peek();
                                topElementLevel = getLevel(topElement);
                            }
                            /*
                             * * 当前扫描的运算符的优先级等于运算符栈顶的运算符优先级: * 1.若当前扫描的运算符为"+、-、*、/、%"
                             * ,则取出操作数栈顶前2个数和运算符栈顶符号进行运算 * 2.若当前扫描的运算符为")",栈顶运算符为"(",则将括号出栈 *
                             * 3.若当前扫描的运算符为"#",说明计算完毕,得到结果
                             */
                            while (curElementLevel == topElementLevel) {
                                if ("+".equals(str[i]) || "-".equals(str[i]) || "*".equals(str[i]) || "/".equals(str[i])
                                        || "%".equals(str[i])) {
                                    // 运算前判断
                                    if (operation.size() < 2 || number.size() < 2) {
                                        operation.clear();
                                        number.clear();
                                        return ERROR;
                                    }
                                    // 计算并将结果入栈
                                    number.add(calc(number.pop(), number.pop(), operation.pop()));
                                    // 运算完之后重新获取运算符栈顶元素
                                    topElement = operation.peek();
                                    topElementLevel = getLevel(topElement);
                                }
                                // 左右括号抵消
                                if (")".equals(str[i]) && "(".equals(topElement)) {
                                    if (operation.size() < 2) {
                                        operation.clear();
                                        number.clear();
                                        return ERROR;
                                    } // 括号出栈
                                    operation.pop(); // 括号出栈后重新获取运算符栈顶元素
                                    topElement = operation.peek();
                                    topElementLevel = getLevel(topElement);
                                    break; // 不加break可以去掉多余的左括号,否则左右括号必须一一对应
                                }
                                if ("#".equals(str[i]) && "#".equals(topElement)) {
                                    if (number.isEmpty()) {
                                        operation.clear();
                                        return ERROR;
                                    } // 得到结果
                                    double result = number.peek();
                                    operation.clear();
                                    number.clear();
                                    return result + "";
                                }
                            }
                            /* * 当前扫描的运算符的优先级大于运算符栈顶的运算符优先级且不是")", * 则将当前扫描到的运算符入栈即可 */
                            if (curElementLevel > topElementLevel && !")".equals(str[i])) { // 入栈
                                operation.add(str[i]);
                            }
                        } else {
                            number.clear();
                            return ERROR;
                        }
                    }
                }
            }
        }
        return ERROR;
    }
 
    /**
     * * 对算数表达式进行初始化处理 * @param str * @return
     */
    private String init(String str) {
        /*
         * * 算式处理,使用正则表达式 * 1.表达式开头的 +、-、*、/、%、. 前面加个0 * 2.连续符号剔除+、-、*、/、%、. *
         * 3.匹配以连续多个左括号"("开头和以" +、-、."结束的字符串,在最后一个左括号的后面加上0
         */
        // step1
        Pattern pattern = Pattern.compile("^[-+*/%\\.].{1,}");// 匹配第一位是 +、-、*、/、. 的字符串
        Matcher matcher = pattern.matcher(str);
        if (matcher.matches()) {// 输出 true,验证通过
            str = "0" + str;
        }
        System.out.println("第一步处理(表达式开头是 +、-、*、/、%、. 前面加个0)后的算式: [ " + str + " ]");
        // step2
        pattern = Pattern.compile("[-+*/%\\.]{2,}");
        matcher = pattern.matcher(str);
        while (matcher.find()) {
            String group = matcher.group();
            String operation = group.substring(0, 1);
            // 重复的运算符
            if (group.replace(operation, "").length() == 0) {// 只剔除连续相同的运算符,否则报错
                str = matcher.replaceFirst(operation);
                matcher = pattern.matcher(str);
            } else
                return ERROR;
        }
        System.out.println("第二步处理(剔除表达式连续重复的运算符)后的算式: [ " + str + " ]"); // step3
        pattern = Pattern.compile("[(][-+\\.]");
        matcher = pattern.matcher(str);
        int startIndex = 0;
        int endIndex = 0;
        int count = 0;
        while (matcher.find()) {// 输出 true,验证通过
            startIndex = matcher.start();
            endIndex = matcher.end(); // 加了多少个0就要将字符索引加多少
            startIndex += count;
            endIndex += count;
            str = str.substring(0, startIndex + 1) + "0" + str.substring(endIndex - 1);
            count++;// 记录加0的个数
        }
        System.out.println("第三步处理(左括号后面是运算符[+-.],在括号后面加0)后的算式: [ " + str + " ]");
        return str;
    }
 
    /** * 拆分表达式 */
    private String[] getCharacters(String str) { // 初始化处理表达式
        str = init(str);
        if (ERROR.equals(str)) {
            return new String[] { ERROR };
        }
        Vector<String> strs = new Vector<String>();
        strs.add("#");
        String charStr = "";
        int startIndex = 0;
        String lastStr = "";
        for (int i = 0; i < str.length(); ++i) {
            char character = str.charAt(i);
            if (isOperation(character)) {
                charStr = str.substring(startIndex, i);
                if (!"".equals(charStr)) {
                    if (isNumber(charStr))
                        strs.add(charStr);
                    else
                        return new String[] { ERROR };
                }
                strs.add(character + "");
                startIndex += charStr.length() + 1;
                lastStr = str.substring(i + 1);
            }
        }
        if (!"".equals(lastStr)) {
            strs.add(lastStr);
        }
        strs.add("#");
        int size = strs.size();
        String[] result = new String[size];
        for (int j = 0; j < size; ++j) {
            result[j] = strs.get(j);
        }
        System.out.println("符号与数字分隔:" + strs);
        strs.clear();
        strs = null;
        return result;
    }
 
    // 得到操作符的优先级别
    private int getLevel(String operate) {
        int level = -1;
        switch (operate) {
        case "#":
            level = 0;
            break;
        case "(":
            level = 1;
            break;
        case ")":
            level = 1;
            break;
        case "+":
            level = 2;
            break;
        case "-":
            level = 2;
            break;
        case "/":
            level = 3;
            break;
        case "%":
            level = 3;
            break;
        case "*":
            level = 4;
            break;
        }
        return level;
    }
 
    /** * 判断是否为运算符号 * @param c * @return */
    private boolean isOperation(char c) {
        if (c == '#' || c == '(' || c == ')' || c == '+' || c == '-' || c == '*' || c == '/' || c == '%')
            return true;
        return false;
    }
 
    /** * 判断是否为运算符号 * @param c * @return */
    private boolean isOperation(String c) {
        if ("#".equals(c) || "(".equals(c) || ")".equals(c) || "+".equals(c) || "-".equals(c) || "*".equals(c)
                || "/".equals(c) || "%".equals(c))
            return true;
        return false;
    }
 
    /** * 判断字符串是否为浮点型数字 * @param str * @return */
    private boolean isNumber(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch (Exception e) {
            // e.printStackTrace();
            return false;
        }
    }
 
    private double calc(double number1, double number2, String operate) {
        double result = 0;
        switch (operate) {
        case "+":
            result = number2 + number1;
            break;
        case "-":
            result = number2 - number1;
            break;
        case "*":
            result = number2 * number1;
            break;
        case "/":
            result = number2 / number1;
            break;
        case "%":
            result = number2 % number1;
            break;
        }
        return result;
    }
 
    public static void main(String[] args) {
        // test
        Calculator c = new Calculator();
        String result = c.calculator(
                "+1*(5+(0-(5*((-10*(2+3)))))++7)+5+((-2+10)-10+15.5%5.8)*2*(-1+2)+10.5+10-10+(-122+3)+15+(50+(+5+6.5*(-2+5)/6.5))*5+(+120-8*5)+45%100");
        System.out.println(result);
    }
}
python+opencv简谱识别音频生成系统源码含GUI界面+详细运行教程+数据 一、项目简介 提取简谱中的音乐信息,依据识别到的信息生成midi文件。 Extract music information from musical scores and generate a midi file according to it. 二、项目运行环境 python=3.11.1 第三方库依赖 opencv-python=4.7.0.68 numpy=1.24.1 可以使用命令 pip install -r requirements.txt 来安装所需的第三方库。 三、项目运行步骤 3.1 命令行运行 运行main.py。 输入简谱路径:支持图片或文件夹,相对路径或绝对路径都可以。 输入简谱主音:它通常在第一页的左上角“1=”之后。 输入简谱速度:即每分钟拍数,同在左上角。 选择是否输出程序中间提示信息:请输入Y或N(不区分大小写,下同)。 选择匹配精度:请输入L或M或H,对应低/中/高精度,一般而言输入L即可。 选择使用的线程数:一般与CPU核数相同即可。虽然python的线程不是真正的多线程,但仍能起到加速作用。 估算字符上下间距:这与简谱中符号的密集程度有关,一般来说纵向符号越稀疏,这个值需要设置得越大,范围通常在1.0-2.5。 二值化算法:使用全局阈值则跳过该选项即可,或者也可输入OTSU、采用大津二值化算法。 设置全局阈值:如果上面选择全局阈值则需要手动设置全局阈值,对于.\test.txt中所提样例,使用全局阈值并在后面设置为160即可。 手动调整中间结果:若输入Y/y,则在识别简谱后会暂停代码,并生成一份txt文件,在其中展示识别结果,此时用户可以通过修改这份txt文件来更正识别结果。 如果选择文件夹的话,还可以选择所选文件夹中不需要识别的文件以排除干扰
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值