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);
        }
    }
}

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: