用两个实现一个计算器程序(代码实现)
这一片博文主要是代码实现,程序分析设计过程我单独写了一篇博文用两个实现一个计算器程序程序设计
1.核心代码实现
1.创建Calculator类
这里我用的栈是自己写的栈,底层是数组所以我这边传入的参数是数组,小伙伴们只要用能实现出栈入栈功能的集合框架都可以。
1.私有属性
public class Calculator {
/**
* 存放数字
*/
private static final ArrayStack<Double> NUMBERS =new ArrayStack<Double>(new Double[3]);
/**
* 存放运算符
*/
private static final ArrayStack<String> OPERATORS =new ArrayStack<String>(new String[2]);
/**
* 空字符串
*/
private static final String EMPTY_STRING ="";
2.验证算式是否合法
整理
去掉括号,并且调用验证方法,如果程序能成功走完验证方法,答应成功的结果
private static String sortEquation(String equation){
equation=equation.replaceAll(" ","");
checkEquation(equation);
System.out.println(equation+"合法!");
return equation;
}
验证
判断算式是否合法(这里不好理解)
public static void checkEquation(String equation){
//定义正则表达式
String regexAll="[0-9|/|\\*|\\-|\\+]";
String regexNumber="[0-9]";
//验证是否有除了加减乘除括号数字以外的符号
if (equation.replaceAll(regexAll,EMPTY_STRING).length()!=0){
throw new RuntimeException("算式“"+equation+"不合法!含有非法的符号!");
}
//定义数字累加器
int add=0;
//验证算式格式是否合法
for (int i = 0; i < equation.length(); i++) {
String value=equation.substring(i,i+1);
//如果是数字,那么累加器++
if(value.replaceAll(regexNumber,EMPTY_STRING).length()==0){
add++;
}
//是运算符
else{
//如果累加器为空,说明运算符是第一位或者上一个value也是运算符,不合法
if (add==0){
throw new RuntimeException("算式“"+equation+"不合法!不能连续使用运算符或运算符不能是第一位!");
}
//清空累加器
add=0;
}
}
//理论最后一次进入循环的是数字add为大于0的数字,如果是运算符,这里add肯定为0,不合理
if (add==0){
throw new RuntimeException("算式“"+equation+"不合法!运算符不能是算式的结尾!");
}
}
3.计算方法
参数准备以及结果接收
弹出一次运算需要的数据并进行计算,然后把运算结果压入数字栈,这里我们称这个方法为。
private static void doCal(){
//获得操作数,注意num2先弹出放在后面
double num2 = NUMBERS.pop();
double num1 = NUMBERS.pop();
String operator = OPERATORS.pop();
double res = cal(num1, num2, operator);
NUMBERS.push(res);
}
具体计算方法
传入两个数字和一个运算符,得到结果返回
private static double cal(double num1,double num2,String operators){
double res = 0;
switch (operators){
case "+":
res=num1+num2;
break;
case "-":
res=num1-num2;
break;
case "*":
res=num1*num2;
break;
case "/":
//注意除的异常
if (num2==0){
throw new ArithmeticException();
}
res=num1/num2;
break;
default:
throw new RuntimeException("bug!");
}
return res;
}
4.计算优先级
默认±的优先级低于* /
private static int priority(String operator){
if("+".equals(operator) || "-".equals(operator)){
return 1;
}
if ("*".equals(operator) || "/".equals(operator)){
return 0;
}
throw new RuntimeException("算式符异常");
}
5.读取字符串
和验证过程如出一辙
public static double calculate(String equation){
//数字累加器
StringBuffer add=new StringBuffer();
//循环读取
for (int i = 0; i < equation.length(); i++) {
String value=equation.substring(i,i+1);
//不是运算符
if (!isOperator(value)){
add.append(value);
}
//是运算符
else {
NUMBERS.push(Double.parseDouble(add.toString()));
add.setLength(0);
//把运算符压入栈中
pushOperator(value);
}
}
//最后一个数字压入栈中
NUMBERS.push(Double.parseDouble(add.toString()));
//手动运算
while(!OPERATORS.isEmpty()){
doCal();
}
return NUMBERS.pop();
}
6.运算符入栈操作
先判断栈是否为空,如果为空直接入栈。如果不为空,那么比较一下优先级,运算符栈的栈顶的优先级大于要新加入的运算符,那么我们执行一次计算 (doCal),如果运算完毕运算符栈还有值,再运算一遍。这是解决前一篇博文所述说的解决优先级一高一低导致栈高度一致增加的关键操作,由于之前的操作是入栈之前的逻辑,我们还没入栈呢!所以最后执行入栈操作。
private static void pushOperator(String operator) {
//不为空
if (!OPERATORS.isEmpty()) {
//优先级大
if (priority((OPERATORS.getTop())) > priority(operator)){
doCal();
if(!OPERATORS.isEmpty()){
doCal();
}
}
//优先级相等
else if (priority((OPERATORS.getTop())) == priority(operator)){
doCal();
}
else{
//TODO
}
}
OPERATORS.push(operator);
}
程序设计截图
- 程序只对外开放了两个方法,一个是计算方法,一个是测试表达式方法(方便测试)
- 首先我们先接收用户的输入(calculate),先去除空格(sortEquation),然后判断表达式是否合法(checkEquation)。如果没有抛出异常,我们循环遍历字符串的每一个元素,如果是连续的数字,我们用stringbuffer拼接起来,如果是算术符号,我们先把stringbuffer里的字符串压入数字栈并清空,然后执行(pushOperator)方法,最后再执行手动的运算(doCal)直到运算符栈为空。
测试代码
package com.atguigu.calculator;
import java.util.Scanner;
/**
* 计算器对象
*/
public class MainApplication {
public static void main(String[] args) {
while (true){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个算式");
double calculate = Calculator.calculate(scanner.nextLine());
System.out.printf("value=%.1f",calculate);
System.out.println();
}
}
}
运行效果
1+2+3+$
Exception in thread "main" java.lang.RuntimeException: 算式“1+2+3+$不合法!含有非法的符号!
1+2+3+4++56
Exception in thread "main" java.lang.RuntimeException: 算式“1+2+3+4++56不合法!不能连续使用运算符或运算符不能是第一位!
1+2+3+4+5+
Exception in thread "main" java.lang.RuntimeException: 算式“1+2+3+4+5+不合法!运算符不能是算式的结尾!
1*5*3/3+5*5
1*5*3/3+5*5合法!
value=30.0
总结:
- 计算器的实现需要一定的Java基础:解析字符串,验证字符串,压栈入栈操作
- 程序的代码量还是蛮大的,如果逻辑不清晰,会导致代码混乱(不算自定义栈,我写了200行)。
- 计算器还有需要改进的地方,比如要支持(),支持表达式出现小数,如何解析表达式中的1.2这个数,以及验证小数点出现的位置是否合法。