package zuizhong; import java.awt.BorderLayout;//边界布局管理器 import java.awt.Color;//提供用于颜色空间的类 import java.awt.Container;//可以放置组件的容器,抽象窗口工具 import java.awt.GridLayout;//布局管理器,用于分割容器,各组件大小由所处区域决定 import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; import java.util.*; import javax.swing.JButton; import javax.swing.Jframe; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.Jtextarea; import javax.swing.border.LineBorder; abstract class CalculatorEngine { static private int Precedence(char op) { switch (op) { case '+': case '-': return 1; // 定义加减运算的优先级为1 case '*': case '/': case '%': return 2; // 定义乘除与取余运算的优先级为2 case '^': return 3; // 定义次方运算的优先级为3 case '!': return 4; // 定义阶乘运算的优先级为4 case '(': case '=': default: return 0; // 定义在栈中的左括号和栈底字符的优先级为0 } } static private String toSuffix(String str) throws Exception { String d=str; StringBuffer strBuf = new StringBuffer();// 存储后缀表达式 Stackstack = new Stack ();// 字符栈,用于处理运算符 stack.push('=');// 压入栈底字符 int i = 0;// 中缀式字符串迭代器 if (str == null || str.equals("") || str.equals("=")) throw new Exception("表达式不能为空"); char ch = str.charAt(i);// 临时字符处理 if (ch == '.') throw new Exception("表达式格式不规范(不能以“.”开头)"); if (str.charAt(str.length() - 1) != '=') throw new Exception("表达式格式不规范(不以“=”结尾)"); if (ch == '-' || ch == '+') strBuf.append("0 ");//正负号首位补零 while (ch != '=') { if (ch == ' ') ch = str.charAt(++i);// 读取下一个字符(忽略空格) else if (ch == '(') { stack.push('(');// 如果是左括号将其压入栈 ch = str.charAt(++i); if (ch == '-' || ch == '+') strBuf.append("0 ");//正负号补零 } else if (ch == ')') {//查看前面是否有左括号 while (stack.peek() != '(') { if (stack.peek() == '=')//stack.peek是查看栈顶的元素但不移除它。pop方法会移除掉栈顶元素 throw new Exception("表达式括号不匹配,缺少“(”"); strBuf.append(stack.pop());//把栈顶元素追加到字符串strBuf后 } stack.pop(); ch = str.charAt(++i); } else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^' || ch == '!' || ch == '%') { char w = stack.peek();// 临时读取栈中的运算符 // 将现在的运算符和栈中的运算符进行优先级比较 while (Precedence(w) >= Precedence(ch)) { strBuf.append(w);//把运算符w追加到字符串strBuf后 stack.pop();//d出该运算符,进行下一个运算符优先级的比较 w = stack.peek(); } stack.push(ch);//将运算符ch压入栈 ch = str.charAt(++i); } else { // 直接将数字和小数点加到后缀式中,把小数点的优先级设定成和数字一样 if (!((ch >= '0' && ch <= '9') || ch == '.')) throw new Exception("表达式出现非法符号"); while ((ch >= '0' && ch <= '9') || ch == '.') { strBuf.append(ch);//把数字ch追加到字符串strBuf后 ch = str.charAt(++i); } strBuf.append(' ');//把空格追加到字符串strBuf后 } } ch = stack.pop(); while (ch != '=') {//检查括号的完整性 if (ch == '(') throw new Exception("表达式括号不匹配,缺少“)”"); else { strBuf.append(ch); ch = stack.pop(); } } strBuf.append('=');//把等于追加到字符串strBuf后 return strBuf.toString();//返回后缀表达式strBuf } static private BigDecimal runSuffix(String str) throws Exception { System.out.println(str);//输入后缀表达式str Stack stack = new Stack ();//进行大数计算的栈 int i = 0;//设置后缀表达式迭代器 BigDecimal num1, num2;//临时大数变量 StringBuffer strBuf;// while (str.charAt(i) != '=') { strBuf = new StringBuffer(); if (str.charAt(i) >= '0' && str.charAt(i) <= '9') { while ((str.charAt(i) >= '0' && str.charAt(i) <= '9') || str.charAt(i) == '.') strBuf.append(str.charAt(i++));//形成数字 try {//Java的异常处理机制 stack.push(new BigDecimal(strBuf.toString())); } catch (Exception e) { throw new Exception("表达式计算数出错"); } } else if (str.charAt(i) == ' ') i++;//忽略空格 else if (str.charAt(i) == '+') { if (stack.size() < 2) throw new Exception("表达式缺少计算数"); num1 = stack.pop(); num2 = stack.pop(); stack.push(num1.add(num2));//加法运算 i++; } else if (str.charAt(i) == '-') { if (stack.size() < 2) throw new Exception("表达式缺少计算数"); num1 = stack.pop(); num2 = stack.pop(); stack.push(num2.subtract(num1));//减法运算 i++; } else if (str.charAt(i) == '*') { if (stack.size() < 2) throw new Exception("表达式缺少计算数"); num1 = stack.pop(); num2 = stack.pop(); stack.push(num1.multiply(num2));//乘法运算 i++; } else if (str.charAt(i) == '%') { if (stack.size() < 2) throw new Exception("表达式缺少计算数"); num1 = stack.pop(); num2 = stack.pop(); try { BigInteger numT1 = num1.toBigIntegerExact(); BigInteger numT2 = num2.toBigIntegerExact(); stack.push(new BigDecimal(numT2.remainder(numT1).toString()));//取余运算 } catch (ArithmeticException e) { throw new Exception("参与取余运算的数只能是整数,且除数不能为0"); } catch (Exception e) { throw new Exception("表达式取余运算出现错误"); } i++; } else if (str.charAt(i) == '^') { if (stack.size() < 2) throw new Exception("表达式缺少计算数"); num1 = stack.pop(); num2 = stack.pop(); try { BigInteger numT = num1.toBigIntegerExact(); if (numT.compareTo(new BigInteger("0")) == numT.compareTo(new BigInteger("999999999"))) throw new ArithmeticException(); stack.push(num2.pow(numT.intValue()));//次方运算 } catch (ArithmeticException e) { throw new Exception("幂的范围只能是0到9999之间,且只能是整数"); } catch (Exception e) { throw new Exception("幂运算出现错误"); } i++; } else if (str.charAt(i) == '!') { if (stack.size() < 1) throw new Exception("表达式缺少计算数"); num1 = stack.pop(); try { BigInteger numT = num1.toBigIntegerExact(); if (numT.compareTo(new BigInteger("0")) == numT.compareTo(new BigInteger("9999"))) throw new ArithmeticException(); int count = numT.intValue(); num2 = new BigDecimal("1"); while (count > 0) num2 = num2.multiply(new BigDecimal(count--));//阶乘运算 stack.push(num2); } catch (ArithmeticException e) { throw new Exception("阶乘的范围只能是0到9999之间,且只能是整数"); } catch (Exception e) { throw new Exception("阶乘运算出现错误"); } i++; } else if (str.charAt(i) == '/') { if (stack.size() < 2) throw new Exception("表达式缺少计算数"); num1 = stack.pop(); num2 = stack.pop(); try { stack.push(num2.divide(num1));//除法运算 } catch (ArithmeticException e) { try { //出现循环小数将其处理为小数点只保留8位 stack.push(num2.divide(num1, 8, RoundingMode.HALF_UP)); } catch (ArithmeticException e2) { throw new Exception("除法运算出现错误(可能是0作了除数)"); } } i++; } } if (stack.size() != 1) throw new Exception("表达式缺少运算符"); return stack.pop(); } static public BigDecimal run(String str) throws Exception {//调用上面的表达式转化函数 String strSuffix = toSuffix(str); return runSuffix(strSuffix); } } class Calculator extends Jframe implements ActionListener, KeyListener { private JPanel eastPanel = new JPanel();//右部面板,用于放置按钮 private JPanel westPanel = new JPanel();//左部面板,用于Use放置文本框和提示标签 private Jtextarea showResult = new Jtextarea(4, 28);//文本框 private Jtextarea History = new Jtextarea(8,28);// 历史记录文本框 private JScrollPane historyUser; private JScrollPane showUser;//为文本框加上拖动条 private JButton[] button = new JButton[24];//24个按钮 private String str = "7 8 9 + 4 5 6 - 1 2 3 * 0 ( ) / . ^2 ^ % ! del clr =";//按钮的字符集 private StringBuffer strBuf;//显示与输入的字符串 private JLabel tips = new JLabel("这里是提示区域");//提示标签 private JLabel label = new JLabel("历史记录"); public Calculator() { this.setTitle("Java简单计算器");//定义窗口标题 this.setSize(560, 300);//窗口大小 this.setResizable(false);//禁止用户调整大小 StringTokenizer strT = new StringTokenizer(str, " ");//将按钮字符集按空格分隔 Container c = this.getContentPane();//获取根容器 showResult.setBorder(new LineBorder(Color.BLACK, 1));//设置文本区域边框 showResult.setLineWrap(true);//文本区域可自动换行 showResult.setEditable(false);//文本区域不可编辑 showResult.addKeyListener(this);//文本区域增加键盘事件监听 showUser = new JScrollPane(showResult);//为文本区域加上拖动条 History.setBorder(new LineBorder(Color.BLACK, 1));//设置文本区域边框 History.setLineWrap(true);//文本区域可自动换行 History.setEditable(false);//文本区域不可编辑 History.addKeyListener(this);//文本区域增加键盘事件监听 historyUser = new JScrollPane(historyUser );//为文本区域加上拖动条 label.setBounds(30, 15, 100, 20);//设置标签位置及大小 this.add(label);// 新建“历史记录”标签 History.setLineWrap(true);//自动换行 History.setWrapStyleWord(true); History.setSelectedTextColor(Color.blue); westPanel.add(showUser, BorderLayout.CENTER); westPanel.add(tips, BorderLayout.SOUTH); westPanel.add(label, BorderLayout.NORTH); westPanel.add(History,BorderLayout.NORTH); eastPanel.setLayout(new GridLayout(6, 4, 2, 2));//布局 for (int i = 0; i < 24; i++) eastPanel.add(button[i] = new JButton(strT.nextToken()));//创建按钮并加到右部面板中 for (int i = 0; i < 24; i++) { button[i].addActionListener(this);//为按钮增加点击事件监听 button[i].addKeyListener(this);//增加键盘事件监听(防止聚焦在按钮上时文本区域无响应) } c.add(eastPanel, BorderLayout.EAST); c.add(westPanel, BorderLayout.CENTER); strBuf = new StringBuffer(); } private void run() { List list=new ArrayList<>(); // Iterator it=list.iterator(); StringBuffer strBuff= strBuf; strBuff.append('=');//表达式规范化以=结尾 try { //计算并且显示 long beforeTime = System.currentTimeMillis(); String strTemp; showResult.setText(strBuff.append(strTemp = (CalculatorEngine.run(strBuff.toString())).toString()).toString()); list.add(strBuff.toString()); int length = list.size(); int i=length; StringBuffer d=null; while(i--!=0) History.setText(list.get(i));//在历史记录框里显示计算表达式及结果 //History.setText(strBuff.toString()); strBuf.setLength(0);//表达式字符串清空 strBuf.append(strTemp);//新的计算保存原来的结果 //History.setText(strBuf+strTemp);//在历史记录框里显示计算表达式及结果 tips.setText("计算已完成"); } catch (Exception ex) { if (ex.getMessage() == null || ex.getMessage().equals("")) tips.setText("发生未知错误"); else tips.setText(ex.getMessage());//将错误输出到提示标签上 } } public void actionPerformed(ActionEvent e) { if (e.getSource() == button[23]) { run();//点击=则计算 //History.setText(+'='+String.valueOf(strBuf)); } else if (e.getSource() == button[21]) { strBuf.setLength(strBuf.length() > 0 ? strBuf.length() - 1 : 0);//删除一个字符,del showResult.setText(strBuf.toString());//显示 } else if (e.getSource() == button[22]) { strBuf.setLength(0);//清空,clr showResult.setText(strBuf.toString());//显示 } else { //计算表达式的形成 String s=strBuf.append(((JButton) e.getSource()).getText()).toString(); showResult.setText(s); } } public void keyPressed(KeyEvent e) { if ((e.getKeyChar() >= '0' && e.getKeyChar() <= '9') || e.getKeyChar() == '.' || e.getKeyChar() == '+' || e.getKeyChar() == '-' || e.getKeyChar() == '*' || e.getKeyChar() == '/' || e.getKeyChar() == '(' || e.getKeyChar() == ')' || e.getKeyChar() == '^' || e.getKeyChar() == '!' || e.getKeyChar() == '%' || e.getKeyChar() == ' ') { //计算表达式的形成 showResult.setText(strBuf.append(e.getKeyChar()).toString()); } else if (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyChar() == '=') { run();//按下回车键或者=,则计算 } else if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { strBuf.setLength(strBuf.length() > 0 ? strBuf.length() - 1 : 0);//删除一个字符,退格键 showResult.setText(strBuf.toString());//显示 //History.setText(strBuf.toString()); } } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } } class test { public static void main(String[] args) { Calculator cframe = new Calculator(); cframe.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE); cframe.setVisible(true); //JOptionPane.showMessageDialog(null, "请注意正确使用java表达式计算器!n"); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)