简单的计算器代码

简单的计算器代码

package p1;


/*
0,使用步骤3步:
1,打开cmd 使用cd命令进入该文件所在的目录(切换盘符命令如“D:”)
2,编译命令javac MyCalc.java -d ./
3,运行命令java p1.MyCalc
*/
import java.awt.*;
import java.awt.event.*;
import java.math.BigDecimal;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Box;


/** *
 *    有待优化的地方 BUG:
 * 1,
 * 2,增加括号运算()
 * 3,末尾去0和小数点
 * 4,文本框全选输入时 覆盖
 * 5,界面优化
 * 6,替换tf1模板
 * 7,
 * @author luther
 * @version *1.0-2019/8.24
 * 	    *1.2-2019/8/25
 * 	    *增加了文本框输入时和Button输入时Esc按键清空功能,和Button输入时Backspace退格功能,
 * 	    *优化了程序对负数符号及算术运算符的识别
 * */
public class MyCalc {
	public static void main(String[] args) {
		
		new Thread(() -> new MyCalc().init(), "线程1").start(); 
	}
	
	/**
	 * @author luther
	 * */
	@FunctionalInterface
	interface SimpleCalculation {
		/**
		 * @param repre 
		 * @return The result of new String
		 */
		String doCalc(String repre);
	}

	//多次需要使用的正则表达式,运算符,减号需要转义,否则表示范围了,如[a-z];运算数,包含整数或小数
	private static final String OPERS = "(?<=\\d)[\\+\\-\\*/]";
	private static final String NUMBER = "(\\-?\\d*\\.?\\d+)";//[(-?\\d*\\.\\d+)(-?\\d+)]
	
	//定义是否需要清空操作,用于下一次输入前清空文本框,输入方式三种,1文本框输入2鼠标点击按钮3键盘输入
	private boolean needCls = true;
	
	//主窗口,使用默认的5方向管理器
	private Frame f = new Frame("計算器");
	
	//4*4按键区
	private Panel p = new Panel(new GridLayout(5, 4, 2, 4));
	
	//存放两个文本框,从上到下
	private Box b = Box.createVerticalBox();
	
	//输入框
	private TextField tf = new TextField("括号功能暂不可用", 30);
	private TextField tf1 = new TextField("Wellcome", 30);
	
	//按键4*4按钮文本
	private static final String[] NAMES = {
			"(", ")", "cls", "del", 
			"7", "8", "9", "+", "4", "5", "6", "-", 
			"1", "2", "3", "*", "0", ".", "=", "/"};
	
	//按键4*4按钮
	private Button[] bs = new Button[NAMES.length];
	
	//二元计算器
	private static SimpleCalculation calc;
	
	//初始化计算器,删除tf1的监听器
	{
		calc = new SimpleCalculation() {
			
			@Override
			public String doCalc(String repre) {
				Matcher m = Pattern.compile(OPERS).matcher(repre);
				m.find();
				String oper = m.group();
				m = Pattern.compile(NUMBER).matcher(repre);
				m.find();
				BigDecimal b1 = new BigDecimal(m.group());
				m = Pattern.compile("(?<=" + OPERS + ")" + NUMBER).matcher(repre);
				m.find();
				BigDecimal b2 = new BigDecimal(m.group());
				
				switch (oper) {
				case "+" :
					return b1.add(b2).doubleValue()+"";
				case "-" :
					return b1.subtract(b2).doubleValue()+"";
				case "*" :
					return b1.multiply(b2).doubleValue()+"";
				case "/" :
					return b1.divide(b2, 20, BigDecimal.ROUND_HALF_UP).doubleValue()+"";
				default :
					return "未知错误2!";
				}
			}
		};
	
		//删除tf1所有监听器,好像没什么用,后期可以考虑用别的模板替换tf1
		ActionListener[] as = tf1.getActionListeners();
		for(ActionListener a : as) {
			tf1.removeActionListener(a);
		}
		
	}
	
	/**
	 * 初始化入口
	 */
	public void init() {
		
		/*输入框背景色,石英色 #D9D9F3 李子色 #EAADEA
		颜色网址:https://zhidao.baidu.com/question/582597145570474685.html
		*/	
		tf1.setBackground(new Color(0x9F5F9F));
		tf.setBackground(new Color(0xD9D9F3));
		b.setBackground(new Color(0xFF7F00));
		p.setBackground(new Color(0xD9D9F0));
		
		//输入框注册按键监听器,功能1,DELETE清空,2,计算后,清空文本区;3,Enter回车键进行计算
		tf.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				
				needCls();
				if(e.getKeyCode() == KeyEvent.VK_DELETE) {
					tf.setText("");
				}
				else if(e.getKeyCode() == KeyEvent.VK_ENTER){
					doCalc();
					//needCls = false;
				}
			}
		});
		
		//4*4按钮监听器
		ActionListener bListener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				needCls(); 
				String cmd = e.getActionCommand();
				if(cmd.equals("=")) {
					doCalc();
				}
				else if(cmd.equals("del")) {
					String s = tf.getText();
					tf.setText(s.length() == 0 ? "" : s.substring(0, s.length() - 1));
				}
				else if(cmd.equals("cls")) {
					tf.setText("");
				}
				else{
					tf.setText(tf.getText() + cmd);
				}
			}
		};
		
		//4*4按键监听器
		KeyAdapter bkListener = new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				String code = KeyEvent.getKeyText(e.getKeyCode());
				
				needCls();
				if(code.equals("Enter")) {
					doCalc();
				}
				else if(code.equals("Backspace")) {
					String s = tf.getText();
					tf.setText(s.length() == 0 ? "" : s.substring(0, s.length() - 1));
				}
				else if(code.equals("Delete")) {
					tf.setText("");
				}
				else if(code.startsWith("NumPad") || code.matches("\\d")) {
					code = code.substring(code.length() - 1);
					tf.setText(tf.getText() + code);
				}
				else{
					//
				}
			}
		};
		
		//初始化按键,注册监听器ActionListener和KeyListener,并组合成4*4按键区
		for(int i = 0; i < NAMES.length; i++) {
			bs[i] = new Button(NAMES[i]);
			bs[i].addActionListener(bListener);
			bs[i].addKeyListener(bkListener);
			bs[i].setBackground(new Color(0xD9D9F3));
			//bs[i].setBounds(0, 0, 1, 2);
			p.add(bs[i]);
		}
		
		//Frame注册WindowListener监听器,实现关闭按钮
		f.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				Runtime.getRuntime().exit(0);
			}
		});
	
		//Frame组合,初始化
		b.add(tf1);
		b.add(tf);
		f.add(b, BorderLayout.NORTH);
		f.add(p);
		f.setLocation(800, 300);
		f.pack();
		f.setVisible(true);
	}
	
	//在执行输入之前,调用此方法执行清空操作,如果需要的话
	private void needCls() {
		
		if(needCls) {
			tf.setText("");
			needCls = false;
		}
	}
	
	/**
	 * 执行计算
	 * 获取计算表达式,显示计算结果
	 */
	private void doCalc() {
		
		tf1.setText(tf.getText() + "=");
		tf.setText(recCalc(tf.getText()));
	}
	
	/**
	 * 递归计算recursive algorithm
	 * @param repre 需要计算的字符串
	 * @return 计算的结果
	 */
	private String recCalc(String exp) {
		
		//去掉小数点和0
		//if(exp.endsWith("0"))
		
		//表达式校验1,只有一个数的表达式,2只需一次计算的表达式,3多次运算的表达式,4无法计算的表达式,
		if(exp.matches(NUMBER)) {
			
			return exp;
		}
		else if(exp.matches(NUMBER + OPERS + NUMBER)) {
			
			//两种情况进行了计算,只需在这里需要清空,下面的递归也会执行到这里
			needCls = true;
			return calc.doCalc(exp); 
			//return simpleCalc(exp);
		}
		else if(exp.matches("^" + NUMBER + "(" + OPERS + NUMBER + ")+$")) {
			
			//两个字符串:子计算结果和新表达式,进入该分支必定是包含2个运算符及以上
			String subResult = "";
			String result = exp;
			
			//获取子表达式,用正则表达式
			Matcher m = Pattern.compile(NUMBER + "[\\*/]" + NUMBER).matcher(exp);
			if (m.find()) {
				
				subResult = m.group();
			}
			else {
				m = Pattern.compile(NUMBER + OPERS + NUMBER).matcher(exp);
				m.find();
				subResult = m.group();
			}
			
			//替换子表达式转换成正则表达式即子字符串的+和*需要转义
			String regex = subResult.replaceFirst("\\b(?=[\\+\\*])", "\\\\");//"\\b+(?=[\\+\\*])", "\\\\"
			
			//把子表达式替换成计算结果
			result = result.replaceFirst(regex, calc.doCalc(subResult));//simpleCalc(subResult)
			
			return recCalc(result);
		}
		else {
			needCls = true;
			return "无法计算";
		}
		
	}

}


  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值