Java实现简易计算器(逆波兰表达式)

本文实例为大家分享了Java实现简易计算器的具体代码,供大家参考,具体内容如下

程序的运行环境为Windows10 ,编译环境为IDEA。

计算器有以下功能和要求:能够计算复杂表达式,实现对多位数和负数以及小数的多则复杂计算

已完善功能(Bug):

1,能够计算大数字,小数,负数

2,小数点,运算符等不能连续输入(例如 ..,++,**等)

3,小数点前没有数字时自动补0并在输入框显示“0.”若小数点前是数字,且前面的数字串里含有".",则不能继续输入小数点(“.”---”0.“ ,1.11后面不能继续输入小数点)

4,‘(’左边和‘)’右边输入数字时,有运算符不做操作,无运算符自动补"*",")"后跟"(',在中间加‘*’(例如“7(”--“7*(”,“)7”--“(*7)”,“(1+1)(2+2)”--“(1+1)*(2+2)”)

5,输入的")"不能多于"(",且相邻()之间不能为空(“()”--X,“((1+2)))--X)

6,能计算负数,符号前面没有数字则补0  (-6-1 -- 0-6-1)

7,运算符除"-"号外不能第一个输入,若不是第一次计算,则可以直接输入,将上一个表达式的结果作为此次表达式的第一个运算数

8,查看历史记录,清空当前记录,清空历史记录,退格操作

运行结果如图:

实现过程:

一、计算器界面设计

1. 初始化界面

通过 this 方法设置包括界面的大小,界面的位置(可根据屏幕设置中间位置),按键北面和中间排版及其颜色和大小,采用GridLayout网格布局

通过循环设置按键的位置,并将运算符加粗,并将所有按键和排版串联到界面上

class Main {
    public static class Calculator extends JFrame implements ActionListener {
        //  初始化界面
        public void init() {
            this.setTitle("计算器");
            history.setEditable(false);
            history.setFont(new Font("宋体", Font.PLAIN, 30));
            this.setSize(477, 577); //界面大小
            this.setLayout(new BorderLayout());
            this.setResizable(false);
            this.setLocationRelativeTo(null);   //界面位置设置居中
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
 
        //北面的控件
        private final JPanel key_north = new JPanel();
        private final JTextField input_text = new JTextField();
        private final JTextArea history = new JTextArea();
        private final JButton c_btn = new JButton("C");
        private final JButton ALLc_btn = new JButton("AC");
        //中间的控件
        private final JPanel center = new JPanel();
 
        //将界面串联
        public Calculator() throws HeadlessException {
            this.init();
            this.addNorthCompent();
            this.addCenterButton();
        }
 
        //添加北面控键
        public void addNorthCompent() {
            this.history.setPreferredSize(new Dimension(350, 200));
            this.input_text.setPreferredSize(new Dimension(450, 30));//输入框的大小
            input_text.setBackground(new Color(127,255,212));
            this.key_north.setBackground(new Color(193,255,193));
            this.history.setBackground(new Color(193,255,120));
            key_north.add(input_text);
            key_north.add(history);
            this.c_btn.setForeground(new Color(0,139,139));//按键颜色
            this.ALLc_btn.setBackground(new Color(0,205,205));
            key_north.add(c_btn);
            key_north.add(ALLc_btn);
            c_btn.setBackground(Color.CYAN);
            c_btn.addActionListener(new ActionListener() {  //为清除操作设置监听
                @Override
                public void actionPerformed(ActionEvent e) {
                    firstint = "";
                    input_text.setText("");
                }
            });
            ALLc_btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    input_text.setText("");
                    firstint = "";
                    hitory = "";
                    history.setText("");
                }
            });
            this.add(key_north, BorderLayout.NORTH);
        }
 
        //添加中间按键
        public void addCenterButton() {
            String key_text = "H()←123+456-789*0.=/";//中间控件排版
            this.center.setLayout(new GridLayout(5, 4));
            String regex = "[+\\-*/=H()←]";
            for (int i = 0; i < 20; i++) {  //初始化按键
                String temp = key_text.substring(i, i + 1);
                JButton key = new JButton();
                key.setFont(new Font("宋体",Font.BOLD,20));
                key.setForeground(new Color(69,139,116));
                key.setBackground(new Color(193,255,193));
                key.setText(temp);
                if (temp.matches(regex)) {   //将运算符加粗并更改颜色
                    key.setFont(new Font("粗体", Font.BOLD, 30));
                    key.setForeground(new Color(102,205,170));
                }
                key.addActionListener(this);
                center.add(key);
            }
            this.add(center, BorderLayout.CENTER);
        }

2. 计算器功能设计

设置监听

设两个空字符串,一个用来保存表达式,另一个用来保存历史记录

为所有按键设置监听功能,将输入的表达式显示到文本框的右边,并实现计算结果,查看历史记录,清空历史记录,计算器表达式退格功能,判断表达式合法性.

@Override
public void actionPerformed(ActionEvent e) {   //监听功能
            String strings = e.getActionCommand();//保存记录
            //JOptionPane.showMessageDialog(this,strings);//监听
 
            if ("0123456789".contains(strings)) {
                if (Objects.equals(firstint, "")) { //输入新的表达式,清除掉上一个表达式结果
                    firstint+=strings;
                    this.input_text.setText(strings);
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
                }else if(strings.equals("0")){
                    if (Objects.equals(firstint, "0")) {
                        this.input_text.setText(firstint);
                    }else {
                        int index = 0;
                        for ( int i=firstint.length()-1;i >=0;i-- ) {
                            if(isSymbol(firstint.substring(index))){
                                index=i;
                            }
                        }
                        if (!firstint.substring(index+1, firstint.length() - 1).equals("0")) {
                            firstint += strings;
                        }
                        this.input_text.setText(firstint);
                    }
                } else if(firstint.charAt(firstint.length()-1)==')'){  //)后输入数字补*号
                    firstint+="*"+strings;
                    this.input_text.setText(firstint);
                }else {this.input_text.setText(input_text.getText() + strings);//将输入的数记录并将之前的数放到前面
                this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
                firstint += strings;
                System.out.println(firstint);}
            } else if (strings.equals(".")) {
                if (Objects.equals(firstint, "")) {
                    if (!Objects.equals(ans, "")) {
                        firstint = ans + ".";
                        this.input_text.setText(firstint);
                    }else {this.input_text.setText(input_text.getText() + "0" + strings);
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT); //自带补0
                    firstint = "0" + strings;}
                } else if(firstint.charAt(firstint.length() - 1) == ')'){ //)后输入小数点补0
                    firstint =firstint+ "*0"+strings;
                    this.input_text.setText(firstint);
                }
                else if (firstint.charAt(firstint.length() - 1) == '.') {   //不能连续小数点
                    this.input_text.setText(firstint);
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                } else if (!ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1))) && !String.valueOf(firstint.charAt(firstint.length() - 1)).equals(".")) {
                    this.input_text.setText(input_text.getText() + "0" + strings);  //前一个既不是数字也不是小数补0
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                    firstint = firstint + "0" + strings;
                } else if (ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1)))) {//如果前面是数字之间输入
                    int count = 0, i = 0;
                    for (i = firstint.length() - 1; i > 0; i--) {     //查找前面的数字串中有没有小数点
                        if (ToPolland.isSymbol(String.valueOf(firstint.charAt(i)))) {
                            break;
                        }//直到遇到下一个运算符时结束查找
                        else if (firstint.charAt(i) == '.') {
                            count++;
                        }
                    }
                    if (count == 0) {      //判断前面的数字串没有小数点
                        this.input_text.setText(input_text.getText() + strings);
                        this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                        firstint = firstint + strings;
                    }
                }
            } else if (strings.matches("[+\\-*/]")) {
                if (Objects.equals(firstint, "")) { //运算符前必须有运算数
                    if (!Objects.equals(ans, "")) {
                        firstint += ans+strings;
                        this.input_text.setText(firstint);
                    }
                    if(strings.equals("-")){   //减号第一个输入当做负号
                        this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                        this.input_text.setText("-");
                        firstint += strings;
                    }
                    //JOptionPane.showMessageDialog(null, "请先输入操作数");
                }else if(firstint.charAt(firstint.length()-1)=='.'){  //小数点后不能跟运算符
                    this.input_text.setText(firstint);
                }
                else if (firstint.charAt(firstint.length() - 1)=='('){ //(后只能跟-号运算符
                    if(strings.equals("-")){
                        firstint+=strings;
                        this.input_text.setText(firstint);
                    }
                }
                else if (ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length() - 1)))&&strings!="-") {
                    this.input_text.setText(firstint);
                } else {
                    this.input_text.setText(input_text.getText() + strings);
                    firstint = firstint + strings;
                    System.out.println(firstint);
                }
            } else if (strings.matches("[()]{1}")) {
                if (strings.equals("(")) {
                    if(Objects.equals(firstint, "") ||firstint.charAt(firstint.length()-1)=='('){
                        firstint+="(";
                        this.input_text.setText(firstint);
                        this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                    }else if(firstint.charAt(firstint.length() - 1) == ')'){
                        firstint+="*"+strings;
                        this.input_text.setText(firstint);
                    } else if(ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length()-1)))){
                        firstint+="*"+strings;
                        this.input_text.setText(firstint);
                    }else if(ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length()-1)))){
                        firstint+=strings;this.input_text.setText(firstint);
                    }
                    System.out.println(firstint);
                } else if (strings.equals(")") && firstint != "") {
                    if(ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length()-1)))){
                        this.input_text.setText(firstint);
                    }else if (firstint.charAt(firstint.length() - 1) != '(') {
                        int count1 = 0, count2 = 1;
                        for (int i = 0; i < firstint.length(); i++) {  //找出()的个数
                            if (firstint.charAt(i) == '(') {
                                count1++;
                            }
                            if (firstint.charAt(i) == ')') {
                                count2++;
                            }
                        }
                        if (count1 >= count2) {  (个数必须大于等于)个数
                            this.input_text.setText(input_text.getText() + strings);
                            firstint = firstint + strings;
                            System.out.println(firstint);
                        }
                    }
                }
            } else if (strings.equals("=")) {   //计算结果
                try {
                    if(firstint.charAt(firstint.length()-1)=='.'){
                        firstint=firstint.substring(0,firstint.length()-2);
                    }System.out.println(firstint);
                    StringBuilder builder = new StringBuilder();
                    List<String> list = toPolland(ToPolland.toList(firstint));
                    list.forEach(builder::append);
                    System.out.println("算式表达式:" + firstint);
                    System.out.println("转逆波兰表达式:" + builder);
                    System.out.println("转逆波兰表达式计算结果:" + firstint + "=" + ToPolland.calculate(list));
                    ans = String.valueOf(ToPolland.calculate(list));
                    this.input_text.setText("" + ToPolland.calculate(list));
                    hitory += firstint + "=" + ToPolland.calculate(list) + "\n";
                    firstint = "";
                } catch (Exception e1) {
                    JOptionPane.showMessageDialog(null, "表达式错误");
                    firstint = "";
                    this.input_text.setText("");
                }
            } else if (strings.equals("H")) {   //查看历史记录
                history.setFont(new Font("宋体", Font.BOLD, 20));
                this.history.setText(hitory);
            } else if (strings.equals("C")) {   //清空当前记录
                firstint = "";
                this.input_text.setText("");
            } else if (strings.equals("AC")) {   //清空历史记录
                firstint = "";
                hitory = "";
                this.history.setText("");
                this.input_text.setText("");
            } else if (strings.equals("←") && firstint.length() != 0) {  //退格
                firstint = firstint.substring(0, firstint.length() - 1);
                System.out.println(firstint);
                this.input_text.setText("" + firstint.substring(0, firstint.length()));
            }
        }
    }

二、表达式求值

1、将中缀表达式转为 list 结构

中缀转后缀表达式时需要先将中缀表达式转为 list 结构,在这个过程中,可以分析表达式的合理性,将表达式进行处理(去掉空格及其他错误的符号),判断表达式的正确性并给予反馈 .          我们处理的时候还需要注意多位数字的处理,可以利用一个字符数组对多位数字和小数进行拼接

//将表达式存入list
public static List<String> toList(String strings) {
        strings = tList(strings);
        if (strings == null || strings.length() <= 0) {
            throw new NullPointerException("表达式不能为空!");
        }
        // 去掉不合法的符号
        strings = strings.replaceAll("\\s*|\t|\r|\n", "");
        List<String> list = new ArrayList<>();
        char[] chars = strings.toCharArray();
        String ch="",str="";
        for (int i = 0; i < chars.length; i++) {
            // 判断是否是数字
            if (!Character.isDigit((chars[i]))) {
                list.add(String.valueOf(chars[i]));
            } else {  //如果是数字,就判断下一个是不是数字,如果是就进行组合(循环),然后录入list
                do {
                    ch = String.valueOf(chars[i]);    //读取一个字符
                    str += ch;              //进行拼接
                    i++;
                    //不是最后一个字符,并且下一个还是数字或者小数点,就进行循环
                } while ((i < strings.length()) && ((chars[i] <= 57
                        && chars[i] >= 48) || '.' == chars[i]));
                list.add(str);//将拼接的字符串录入到list
                str = "";i--;
                System.out.println(list);//这里一定要将str置位初值
            }
        }
        return list;
    }

需要注意的是当输入的表达式中存在负数时,需要在负号前面补0,或者将负号后面的表达式中的一个计算符取反,否则转为逆波兰表达式后得不到正确的结果。

//表达式中存在负数时,后面的逆波兰表达式算法无法得到正确结果,需要补0
public static String tList(String strings) {
        String stringBuilder = "";
        if(strings.charAt(0)=='-'){//如果第一个字符是‘-',在负号前面补0
            stringBuilder+= "0";
        }
        stringBuilder+=strings.charAt(0); //将第一个‘-'号接到0后面
        //如果遇到负号,并且负号前面的符号不是数字,在负号前面补0
        for (int i = 1; i < strings.length(); i++) {
            if (strings.charAt(i) == '-' && (isNumber(String.valueOf(strings.charAt(i - 1))) == false)) {
                stringBuilder += "0" + strings.charAt(i);
            } else stringBuilder += strings.charAt(i);//没有负号则直接拼接
        }
        return stringBuilder;
    }

2、逆波兰表达式的转化(单栈法)

采用单栈来和一个队列对表达式进行操作,也可以采用双栈法处理表达式

构造判断数字,计算符以及优先级的方法

实现代码如下:

//转逆波兰表达式
public static List<String> toPolland(List<String> list) {
        Stack<String> s1 = new Stack();
        List<String> s2 = new ArrayList<>();
 
        //  从左至右扫描中缀表达式;
        for (String item : list) {
            // 遇到操作数时,将其压s2;
            if (Pattern.matches("-?[0-9]+(\\.[0-9]+)?", item)) {
                s2.add(item);
            }//遇到操作符时,比较其与栈顶的操作符的优先级
            if (isSymbol(item)) {
                while (s1.size() > 0 && isSymbol(s1.peek()) && priority(item) <= priority(s1.peek())) {
                    s2.add(s1.pop());
                }
                s1.push(item);
            }
            if (item.equals("(")) { //右括号直接入栈
                s1.push(item);
            }
            if (item.equals(")")) {  //遇到右括号,将左括号之前的操作符全部出栈
                while (!s1.peek().equals("(")) {
                    s2.add(s1.pop());
                }
                // 将左边的括号,弹栈
                s1.pop();
            }
        }
        while (s1.size() > 0) {  //将剩余的操作符全部入栈
            s2.add(s1.pop());
        }
        return s2;
    }

判断数字和运算符已经比较运算符优先级:

//判断是否为数字
public static boolean isNumber(String str) {
        return Pattern.matches("-?[0-9]+(\\.[0-9]+)?", str);
    }
    //是否是运算符
    public static boolean isSymbol(String str) {
                return "+-*/".contains(str);
    }
    //返回运算符的优先级
    public static int priority(String value) {
        if ("+-".contains(value)) {
            return 1;
        } else if ("*/".contains(value)) {
            return 2;
        } else {
            throw new RuntimeException("暂不支持操作符:" + value);
        }
    }

3、逆波兰表达式(后缀表达式)的计算

首先准备一个栈Res_Stack.

1、从左开始向右遍历后缀表达式的元素。

2、如果取到的元素是操作数,直接入栈Res_Stack,如果是运算符,从栈中弹出2个数进行运算,然后把运算结果入栈

3、当遍历完后缀表达式时,计算结果就保存在栈里了。

算法思想:

代码如下:

//逆波兰表达式的计算
public static BigDecimal calculate(List<String> nipollands) {
        if (nipollands == null || nipollands.size() <= 1) {
            throw new NullPointerException("逆波兰表达式列表不能为空!");
        }
        Stack<BigDecimal> stack = new Stack();
        for (String nipolland : nipollands) {
            if (isNumber(nipolland)) {   //数字直接入栈
                stack.push(new BigDecimal(nipolland));
            } else {      //遇到操作符取出两个数进行对应的计算,并将计算结果入栈
                BigDecimal number1 = stack.pop();
                BigDecimal number2 = stack.pop();
                BigDecimal result;
                switch (nipolland) {
                    case "+" -> result=number2.add(number1);
                    case "-" -> result=number2.subtract(number1);
                    case "*" -> result=number2.multiply(number1);
                    case "/" -> result=number2.divide(number1, 3,RoundingMode.HALF_UP);
                    default -> throw new RuntimeException("不合法操作符:" + nipolland);
                }
                stack.push(result);//遍历字符串后得到的栈顶既为逆波兰表达式计算结果
            }
        }
        return stack.pop();
    }

完整代码:

package com.company;
 
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
 
import static com.company.ToPolland.toPolland;
 
class Main {
    public static class Calculator extends JFrame implements ActionListener {
        //  初始化界面
        public void init() {
            this.setTitle("计算器");
            history.setEditable(false);
            history.setFont(new Font("宋体", Font.PLAIN, 30));
            this.setSize(477, 577); //界面大小
            this.setLayout(new BorderLayout());
            this.setResizable(false);
            this.setLocationRelativeTo(null);   //界面位置设置居中
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
 
        //北面的控件
        private final JPanel key_north = new JPanel();
        private final JTextField input_text = new JTextField();
        private final JTextArea history = new JTextArea();
        private final JButton c_btn = new JButton("C");
        private final JButton ALLc_btn = new JButton("AC");
        //中间的控件
        private final JPanel center = new JPanel();
 
        //将界面串联
        public Calculator() throws HeadlessException {
            this.init();
            this.addNorthCompent();
            this.addCenterButton();
        }
 
        //添加北面控键
        public void addNorthCompent() {
            this.history.setPreferredSize(new Dimension(350, 200));
            this.input_text.setPreferredSize(new Dimension(450, 30));//输入框的大小
            input_text.setBackground(new Color(127,255,212));
            this.key_north.setBackground(new Color(193,255,193));
            this.history.setBackground(new Color(193,255,120));
            key_north.add(input_text);
            key_north.add(history);
            this.c_btn.setForeground(new Color(0,139,139));//按键颜色
            this.ALLc_btn.setBackground(new Color(0,205,205));
            key_north.add(c_btn);
            key_north.add(ALLc_btn);
            c_btn.setBackground(Color.CYAN);
            c_btn.addActionListener(new ActionListener() {  //为清除操作设置监听
                @Override
                public void actionPerformed(ActionEvent e) {
                    firstint = "";
                    input_text.setText("");
                }
            });
            ALLc_btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    input_text.setText("");
                    firstint = "";
                    hitory = "";
                    history.setText("");
                }
            });
            this.add(key_north, BorderLayout.NORTH);
        }
 
        //添加中间按键
        public void addCenterButton() {
            String key_text = "H()←123+456-789*0.=/";//中间控件排版
            this.center.setLayout(new GridLayout(5, 4));
            String regex = "[+\\-*/=H()←]";
            for (int i = 0; i < 20; i++) {  //初始化按键
                String temp = key_text.substring(i, i + 1);
                JButton key = new JButton();
                key.setFont(new Font("宋体",Font.BOLD,20));
                key.setForeground(new Color(69,139,116));
                key.setBackground(new Color(193,255,193));
                key.setText(temp);
                if (temp.matches(regex)) {   //将运算符加粗并更改颜色
                    key.setFont(new Font("粗体", Font.BOLD, 30));
                    key.setForeground(new Color(102,205,170));
                }
                key.addActionListener(this);
                center.add(key);
            }
            this.add(center, BorderLayout.CENTER);
        }
 
        private String firstint = "";//保存表达式
        static String hitory = "";//保存历史记录
        static String ans = "";
 
        @Override
        public void actionPerformed(ActionEvent e) {   //监听功能
            String strings = e.getActionCommand();//保存记录
            //JOptionPane.showMessageDialog(this,strings);//监听
            if ("0123456789".contains(strings)) {
                if (firstint == "") {
                    firstint+=strings;
                    this.input_text.setText(strings);
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
                }else if(firstint.charAt(firstint.length()-1)==')'){
                    firstint+="*"+strings;
                    this.input_text.setText(firstint);
                }else {this.input_text.setText(input_text.getText() + strings);//将输入的数记录并将之前的数放到前面
                this.input_text.setHorizontalAlignment(JTextField.RIGHT);//显示到右边
                firstint += strings;
                System.out.println(firstint);}
            } else if (strings.equals(".")) {
                if (firstint == "") {
                    this.input_text.setText(input_text.getText() + "0" + strings);
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                    firstint = "0" + strings;
                } else if(firstint.charAt(firstint.length() - 1) == ')'){
                    firstint =firstint+ "*0"+strings;
                    this.input_text.setText(firstint);
                }
                else if (firstint.charAt(firstint.length() - 1) == '.') {   //不能连续小数点
                    this.input_text.setText(firstint);
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                } else if (!ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1))) && String.valueOf(firstint.charAt(firstint.length() - 1)) != ".") {
                    this.input_text.setText(input_text.getText() + "0" + strings);  //前一个既不是数字也不是小数补0
                    this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                    firstint = firstint + "0" + strings;
                } else if (ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length() - 1)))) {//如果前面是数字之间输入
                    int count = 0, i = 0;
                    for (i = firstint.length() - 1; i > 0; i--) {     //查找前面的数字串中有没有小数点
                        if (ToPolland.isSymbol(String.valueOf(firstint.charAt(i)))) {
                            break;
                        }//直到遇到下一个运算符时结束查找
                        else if (firstint.charAt(i) == '.') {
                            count++;
                        }
                    }
                    if (count == 0) {      //判断前面的数字串没有小数点
                        this.input_text.setText(input_text.getText() + strings);
                        this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                        firstint = firstint + strings;
                    }
                }
            } else if (strings.matches("[+\\-*/]{1}")) {
                if (firstint == "") {
                    if (ans != "") {
                        firstint += ans+strings;
                        this.input_text.setText(firstint);
                    }
                    if(strings=="-"){
                        firstint += strings;
                        this.input_text.setText(input_text.getText()+strings);
                    }
                    //JOptionPane.showMessageDialog(null, "请先输入操作数");
                } else if (ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length() - 1)))&&strings!="-") {
                    JOptionPane.showMessageDialog(null, "表达式错误");
                } else {
                    this.input_text.setText(input_text.getText() + strings);
                    firstint = firstint + strings;
                    System.out.println(firstint);
                }
            } else if (strings.matches("[()]{1}")) {
                if (strings.equals("(")) {
                    if(firstint==""){
                        firstint+="(";
                        this.input_text.setText(firstint);
                        this.input_text.setHorizontalAlignment(JTextField.RIGHT);
                    }else if(ToPolland.isNumber(String.valueOf(firstint.charAt(firstint.length()-1)))){
                        firstint+="*"+strings;
                        this.input_text.setText(firstint);
                    }else if(ToPolland.isSymbol(String.valueOf(firstint.charAt(firstint.length()-1)))){
                        firstint+=strings;this.input_text.setText(firstint);
                    }
                    System.out.println(firstint);
                } else if (strings.equals(")") && firstint != "") {
                    if (firstint.charAt(firstint.length() - 1) != '(') {
                        int count1 = 0, count2 = 1;
                        for (int i = 0; i < firstint.length(); i++) {
                            if (firstint.charAt(i) == '(') {
                                count1++;
                            }
                            if (firstint.charAt(i) == ')') {
                                count2++;
                            }
                        }
                        if (count1 >= count2) {
                            this.input_text.setText(input_text.getText() + strings);
                            firstint = firstint + strings;
                            System.out.println(firstint);
                        }
                    }
                }
            } else if (strings.equals("=")) {   //计算结果
                try {
                    System.out.println(firstint);
                    StringBuilder builder = new StringBuilder();
                    List<String> list = toPolland(ToPolland.toList(firstint));
                    list.forEach(builder::append);
                    System.out.println("算式表达式:" + firstint);
                    System.out.println("转逆波兰表达式:" + builder);
                    System.out.println("转逆波兰表达式计算结果:" + firstint + "=" + ToPolland.calculate(list));
                    ans = String.valueOf(ToPolland.calculate(list));
                    this.input_text.setText("" + ToPolland.calculate(list));
                    hitory += firstint + "=" + ToPolland.calculate(list) + "\n";
                    firstint = "";
                } catch (Exception e1) {
                    JOptionPane.showMessageDialog(null, "表达式错误");
                    firstint = "";
                    this.input_text.setText("");
                }
            } else if (strings.equals("H")) {   //查看历史记录
                history.setFont(new Font("宋体", Font.BOLD, 20));
                this.history.setText(hitory);
            } else if (strings.equals("C")) {   //清空当前记录
                firstint = "";
                this.input_text.setText("");
            } else if (strings.equals("AC")) {   //清空历史记录
                firstint = "";
                hitory = "";
                this.history.setText("");
                this.input_text.setText("");
            } else if (strings.equals("←") && firstint.length() != 0) {  //退格
                firstint = firstint.substring(0, firstint.length() - 1);
                System.out.println(firstint);
                this.input_text.setText("" + firstint.substring(0, firstint.length()));
            }
        }
    }
 
    public static void main(String[] args) {
        Calculator carculator = new Calculator();
        carculator.setVisible(true);
    }
public class ToPolland {
    //表达式中存在负数时,后面的逆波兰表达式算法无法得到正确结果,需要补0
    public static String tList(String strings) {
        String stringBuilder = "";
        if(strings.charAt(0)=='-'){//如果第一个字符是‘-',在负号前面补0
            stringBuilder+= "0";
        }
        stringBuilder+=strings.charAt(0); //将第一个‘-'号接到0后面
        //如果遇到负号,并且负号前面的符号不是数字,在负号前面补0
        for (int i = 1; i < strings.length(); i++) {
            if (strings.charAt(i) == '-' && (!isNumber(String.valueOf(strings.charAt(i - 1))))) {
                stringBuilder += "0" + strings.charAt(i);
            } else stringBuilder += strings.charAt(i);//没有负号则直接拼接
        }
        return stringBuilder;
    }
    //将表达式存入list
    public static List<String> toList(String strings) {
        strings = tList(strings);
        if (strings == null || strings.length() <= 0) {
            throw new NullPointerException("表达式不能为空!");
        }
        // 去掉不合法的符号
        strings = strings.replaceAll("\\s*|\t|\r|\n", "");
        List<String> list = new ArrayList<>();
        char[] chars = strings.toCharArray();
        String ch="",str="";
        for (int i = 0; i < chars.length; i++) {
            // 判断是否是数字
            if (!Character.isDigit((chars[i]))) {
                list.add(String.valueOf(chars[i]));
            } else {  //如果是数字,就判断下一个是不是数字,如果是就进行组合(循环),然后录入list
                do {
                    ch = String.valueOf(chars[i]);    //读取一个字符
                    str += ch;              //进行拼接
                    i++;
                    //不是最后一个字符,并且下一个还是数字或者小数点,就进行循环
                } while ((i < strings.length()) && ((chars[i] <= 57
                        && chars[i] >= 48) || '.' == chars[i]));
                list.add(str);//将拼接的字符串录入到list
                str = "";i--;
                System.out.println(list);//这里一定要将str置位初值
            }
        }
        return list;
    }
    //转逆波兰表达式
    public static List<String> toPolland(List<String> list) {
        Stack<String> s1 = new Stack();
        List<String> s2 = new ArrayList<>();
        //  从左至右扫描中缀表达式;
        for (String item : list) {
            // 遇到操作数时,将其压s2;
            if (Pattern.matches("-?[0-9]+(\\.[0-9]+)?", item)) {
                s2.add(item);
            }//遇到操作符时,比较其与栈顶的操作符的优先级
            if (isSymbol(item)) {
                while (s1.size() > 0 && isSymbol(s1.peek()) && priority(item) <= priority(s1.peek())) {
                    s2.add(s1.pop());
                }
                s1.push(item);
            }
            if (item.equals("(")) { //右括号直接入栈
                s1.push(item);
            }
            if (item.equals(")")) {  //遇到右括号,将左括号之前的操作符全部出栈
                while (!s1.peek().equals("(")) {
                    s2.add(s1.pop());
                }
                s1.pop();// 将左边的括号,弹栈
            }
        }
        while (s1.size() > 0) {  //将剩余的操作符全部入栈
            s2.add(s1.pop());
        }
        return s2;
    }
    //逆波兰表达式的计算
    public static BigDecimal calculate(List<String> nipollands) {
        if (nipollands == null || nipollands.size() <= 1) {
            throw new NullPointerException("逆波兰表达式列表不能为空!");
        }
        Stack<BigDecimal> stack = new Stack();
        for (String nipolland : nipollands) {
            if (isNumber(nipolland)) {   //数字直接入栈
                stack.push(new BigDecimal(nipolland));
            } else {      //遇到操作符取出两个数进行对应的计算,并将计算结果入栈
                BigDecimal number1 = stack.pop();
                BigDecimal number2 = stack.pop();
                BigDecimal result;
                switch (nipolland) {
                    case "+" -> result=number2.add(number1);
                    case "-" -> result=number2.subtract(number1);
                    case "*" -> result=number2.multiply(number1);
                    case "/" -> result=number2.divide(number1, 3,RoundingMode.HALF_UP);
                    default -> throw new RuntimeException("不合法操作符:" + nipolland);
                }
                stack.push(result);//遍历字符串后得到的栈顶既为逆波兰表达式计算结果
            }
        }
        return stack.pop();
    }
    //判断是否为数字
    public static boolean isNumber(String str) {
        return Pattern.matches("-?[0-9]+(\\.[0-9]+)?", str);
    }
    //是否是运算符
    public static boolean isSymbol(String str) {
        return "+-*/".contains(str);
    }
    //返回运算符的优先级
    public static int priority(String value) {
        if ("+-".contains(value)) {
            return 1;
        } else if ("*/".contains(value)) {
            return 2;
        } else {
            throw new RuntimeException("暂不支持操作符:" + value);
        }
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java实现科学计算器的全过程与代码

    目录 介绍 实现思路 实现过程和代码 1.界面设计 2.栈,中缀转后缀 3.判断错误 4.计算后缀表达式 5.事件监听器 完整代码 总结 介绍 本次设计的是一个有33个按钮的科学计算器.可以进行加,减,乘,除,开根号,阶乘,次方,百分号,对数,三角函数的计算. 实现思路 通过点击按钮可以得到一个算术表达式,并且它是一个字符串类型,然后需要做的就是把这个字符串转化为计算机可计算的形式.这里就需要用到中缀表达式转化为后缀表达式.转化完之后通过栈来一步步的进行输出和计算,最后输出结果. 实现过程和代码

  • java gui实现计算器小程序

    本文实例为大家分享了java gui实现计算器小程序的具体代码,供大家参考,具体内容如下 废话不多说 , 直接贴代码 , 有详细的注释 , 我也是刚学GUI没多久 这个是效果图 : 代码: package gui; /** * 导入所需要的包 **/ import java.awt.*; // 这个是java的gui编程里面一个很重要的包 import java.awt.event.*; // 用来处理事件所需要 import java.util.Stack; // 栈 , 我用来处理运算的 p

  • java GUI实现加法计算器

    本文实例为大家分享了java GUI实现加法计算器的具体代码,供大家参考,具体内容如下 1.写出一个简易计算器需要的组件 2.先出监听事件类 public class TextCalculator01 { public static void main(String[] args) { new MyCalculator(); } } //计算器类 class MyCalculator extends Frame{ public MyCalculator() { //三个文本框 TextField

  • java实现计算器模板及源码

    计算器实现了大部分基础功能:基本运算,菜单栏选项,并且拓展了普通型和科学兴选项等等,读者可以在此基础上进行修改和拓展.其他具体实现方法可以看源码,里面有详细的概述,代码框架清晰. 运行环境:win10 Eclipse IDE for Java Developers - 2020-06 下面是计算器的视图: import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; impo

  • Java利用栈实现简易计算器功能

    利用栈实现一个简易计算器(Java实现),供大家参考,具体内容如下 一.思路分析 当我们输入一个类似于“7*2+100-5+3-4/2”的简单中缀表达式时,我们的编译器能够利用我们所编写的代码将这个表达式扫描并计算出其结果 在这个表达式中主要有两种元素,一种是数字,一种是符号,那么我们就需要创建两个栈结构存储数据 数栈numStack:存放数 符号栈operStack:存放运算符 1.首先我们需要定义一个index(索引),来遍历我们的表达式 2.如果扫描到一个数字,就直接入数栈 3.如果扫描到

  • java实现简易的计算器界面

    如何用java写一个简易的计算器界面 前言(与本节重点无关可以忽视) 最近了解了一些界面窗口知识,在老师一步步的悉心教导下我却又一次地走向了迷茫——陌生,理解不充分,照搬.咳咳,但是经过几天的拆解,琢磨,实践,我也渐渐粗浅地认识到了一些本质问题.当时教写的是登录界面,所以这次我打算写一个计算器界面来检测一下自己是不是依然一头雾水. 基本准备 首先给类取名CaculatorInterface(计算器界面) package kallen1014; public class CalculatorInt

  • Java GUI图形界面开发实现小型计算器流程详解

    目录 一.设计目标 二.界面设计 三.功能实现 四.全部代码 五.功能测试 六.小结 一.设计目标 (1)主要功能:实现简单的加.减.乘.除等双目运算,和开平方.百分数等单目运算 (2)辅助功能:按钮“C”实现清空文本框:按钮“←”实现退格,删除文本框中最右边的一个字符 二.界面设计 创建“面板对象”,并设置其布局管理方式为5行4列的GridLayout布局方式,以用于容纳20个按钮.文本框和容纳20个按钮组件的面板则使用边界布局方式分别将其布局到窗体BorderLayout.NORTH和中央位

  • java swing实现简单计算器界面

    本文实例为大家分享了java swing实现简单计算器界面的具体代码,供大家参考,具体内容如下 已经学习了一部分的swing知识,现在综合运用里面的部分知识来实现一个计算器的界面. 运用到的知识: 1.常用顶层容器 JFrame类 的使用2.常用中间容器 JPanel类 的使用3.单行文本框的实现类 JTextField类 的使用4.按钮的实现类 JButton类 的使用5.边框布局管理器 的使用6.网格布局管理器 的使用 基本思路: 1.创建1个窗口f12.创建1个文本框t13.创建内层面板p

  • Java实现简易计算器(逆波兰表达式)

    本文实例为大家分享了Java实现简易计算器的具体代码,供大家参考,具体内容如下 程序的运行环境为Windows10 ,编译环境为IDEA. 计算器有以下功能和要求:能够计算复杂表达式,实现对多位数和负数以及小数的多则复杂计算 已完善功能(Bug): 1,能够计算大数字,小数,负数 2,小数点,运算符等不能连续输入(例如 ..,++,**等) 3,小数点前没有数字时自动补0并在输入框显示“0.”若小数点前是数字,且前面的数字串里含有".",则不能继续输入小数点(“.”---”0.“ ,1

  • Java编程实现逆波兰表达式代码示例

    逆波兰表达式 定义:传统的四则运算被称作是中缀表达式,即运算符实在两个运算对象之间的.逆波兰表达式被称作是后缀表达式,表达式实在运算对象的后面. 逆波兰表达式: a+b ---> a,b,+ a+(b-c) ---> a,b,c,-,+ a+(b-c)*d ---> a,b,c,-,d,*,+ a+d*(b-c)--->a,d,b,c,-,*,+ a=1+3 ---> a=1,3 + http=(smtp+http+telnet)/1024 写成什么呢? http=smtp,

  • Python实现处理逆波兰表达式示例

    本文实例讲述了Python实现处理逆波兰表达式.分享给大家供大家参考,具体如下: 中文名: 逆波兰表达式 外文名: Reverse Polish Notation 别名: 后缀表达式 逆波兰表达式又叫做后缀表达式.在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称为中缀表示.波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法,按此方法,每一运算符都置于其运算对象之后,故称为后缀表示.这个知识点在数据结构和编译原理这两门课程中都有介绍.它的优

  • java实现简易计算器功能

    本文为大家分享了java实现简易计算器功能,具体内容如下 题目: 编写一个模拟计算器的程序.在面板中添加一个文本框(显示按键及运算结果). 10个数字按钮(0~9).4个运算按钮(加.减.乘.除).一个等号按钮.一个清除按钮, 要求将按键和结果显示在文本框中. 代码过程展示: import java.awt.Container; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.Action

  • C++代码实现逆波兰表达式

    本文实例为大家分享了C++实现逆波兰表达式的具体代码,供大家参考,具体内容如下 当我们输入一个数学表达式,是中缀表达式,我们首先转换为后缀表达式(逆波兰表达式),然后再进行求值. 在<大话数据结构>的104-100页有详细的介绍,下面是我理解之后的代码实现. 代码思路: (1)首先对输入的中缀表达式合法性进行判断,bool isStringLegal(const char* str); 函数实现. (2)然后把中缀表达式转换为后缀表达式. (3)根据后缀表达式求出结果,double getTh

  • C++实现LeetCode(150.计算逆波兰表达式)

    [LeetCode] 150.Evaluate Reverse Polish Notation 计算逆波兰表达式 Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, /. Each operand may be an integer or another expression. Note: Division between two integ

  • C++实现逆波兰表达式的例题详解

    目录 1. 题目描述 2. 解题思路 3. 动图演示 4. 代码实现 1. 题目描述 2. 解题思路 逆波兰表达式由波兰的逻辑学家卢卡西维兹提出,它的特点是:没有括号,运算符总是放在和它相关的操作数之后.因此,逆波兰表达式也称后缀表达式,它严格遵循「从左到右」的运算. 在我们平时生活中,使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ). 该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) . 计算逆波兰表达式的值时,使用一个栈存储操作数,从

  • 逆波兰计算器(Java实现)

    之前的一篇博客中,讲的是用栈实现了中缀表达式的简易计算器,对于我们人来讲,中缀表达式是一种比较直观,而且非常好计算的一种形式,但对于计算器来讲,非常的难去看懂.所以,下面我讲下逆波兰计算器的Java实现. 逆波兰式(后缀表达式) 逆波兰表达式又叫做后缀表达式.逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasewicz)于1929年首先提出的一种表达式的表示方法 [1]  .后来,人们就把用这种表示法写出的表达式称作"逆波兰表达式".逆波兰表达式把运算量写在前面,把算符写在后面

  • python实现逆波兰计算表达式实例详解

    本文实例讲述了python实现逆波兰计算表达式的方法.分享给大家供大家参考.具体分析如下: 逆波兰表达式又叫做后缀表达式.在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示.波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法.按此方法,每一运算符都置于其运算对象之后,故称为后缀表示. # -*- coding: utf-8 -*- symbol_priority = {} symbol_priority[0] = ['#']

  • Java编写简单计算器的完整实现过程

    前言 本文用Java的swing来实现一个简单计算器,主要内容为图形用户界面GUI的实现以及运算表达式核心算法的设计编写. 程序运行环境为Windows10 ,编译环境为MyEclipse . 一.具体功能: 1.:输入,输出 输入:允许输入带有括号的完整计算式(例 8*(4-95)+5÷2*e-pi) 输出:输出Double类型的结果 输出:整个运算表达式并保存于历史记录中 2.:功能 基本的加,减,乘,除,四则运算  平方运算  开方运算  求余运算 最终界面如下图: 除了常规的数字按钮和运

随机推荐