废话不多说,直接上代码
主类:Main.java
import java.util.Scanner;
/*
*
* 可能这个程序有很多不必要的步骤,必须为啥不把下面两个方法写在一个main方法中,
* 在这解释一下,这是为了后期好在里面添加一些我们需要的东西,便于维护
* 虽然只是一个小项目,但是养成习惯是好多(或许我现在还年轻,陷入误区,希望自行思考)
*
* 多谢多谢,勿喷
*
* */
public class Main {
public static void main(String[] args) {
String str = getInputExpression();
run(str);
}
//获取输入的中缀表达式
public static String getInputExpression(){
System.out.println("请输入表达式:该表达式不能计算负数,");
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
return str;
}
//开始计算,计算结果直接输入
public static void run(String str){
Calcutor calcutor = new Calcutor(str);
if(calcutor.checkStr()){
String result = calcutor.calResult();
System.out.println(result);
return ;
}else{
return ;
}
}
}
Calcutor.java
import java.util.ArrayList;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/*
* 该计算不包含负数运算
* 此段代码中命名自我感觉不怎么规范,但是能力有限,实在没什么经验,不晓得怎么改比较好
* 经验不足
* */
public class Calcutor {
private String inputString;
public Calcutor() {
}
public Calcutor(String inputString) {
this.inputString = inputString;
}
public String getInputString() {
return inputString;
}
public void setInputString(String inputString) {
this.inputString = inputString;
}
//将中缀表达式转化为后缀表达式,返回类型为字符串
public ArrayList<String> changeSuffix(){
Stack<Character> operatorStack = new Stack(); //存放操作数的栈
ArrayList<String> resultStr = new ArrayList<>(); //存放结果的字符串数组
String str = this.inputString; //得到输入的中缀表达式
String numStr = ""; // 遍历中缀表达式是存放每一个数的字符串
int i = 0; //遍历中缀时的下表
char nowChar = str.charAt(i); //得到具体每一个字符
operatorStack.push('='); //将栈底等于‘=’
while(nowChar != '=' || !(operatorStack.peek() == '=')){ //循环遍历,
nowChar = str.charAt(i);
//如果此时字符为0-9或者是小数点
if(nowChar >= '0' && nowChar <= '9' || nowChar == '.'){
//记录每一个数,并保存在numStr中
while(nowChar >= '0' && nowChar <= '9' || nowChar == '.'){
numStr += nowChar;
i ++;
nowChar = str.charAt(i);
}
//将数入栈
resultStr.add(numStr);
//制空,便于下次使用
numStr = "";
//字符为+-
}else if(nowChar == '+' || nowChar == '-'){
//此时判断优先级,在栈顶如果是+-*/,则将前面的出栈,并将现在的操作符入栈,循环的作用是为了连续出栈
while(operatorStack.peek() == '*' || operatorStack.peek() == '/' || operatorStack.peek() == '+' || operatorStack.peek() == '-' ){
String temp = String.valueOf(operatorStack.pop());
resultStr.add(temp);
}
operatorStack.push(nowChar);
i ++;
//如果此时为操作符
}else if(nowChar == '*' || nowChar == '/'){
while(operatorStack.peek() == '*' || operatorStack.peek() == '/'){
String temp = String.valueOf(operatorStack.pop());
resultStr.add(temp);
}
operatorStack.push(nowChar);
i ++;
//(入栈,什么都不用做
}else if(nowChar == '('){
operatorStack.push(nowChar);
i ++;
//)将操作符栈顶出栈,知道遇到了(
}else if(nowChar == ')'){
while(operatorStack.peek() != '('){
String temp = String.valueOf(operatorStack.pop());
resultStr.add(temp);
}
i ++;
operatorStack.pop();
//这里默认中缀结束符为 = ,如果栈中只有'=',那么结束,成功转化
}else if(nowChar == '=' && operatorStack.peek() != '='){
i = str.length()-1;
while(operatorStack.peek() != '='){
String temp = String.valueOf(operatorStack.pop());
resultStr.add(temp);
}
//避免以后还有情况,预留一个else,此时为空
}else{
}
}
return resultStr;
}
//计算后缀表达式
public String calResult(){
String result = ""; //记录结果
Stack<String> strStack = new Stack<>(); //将数字入栈
ArrayList<String> list = changeSuffix(); //得到后缀表达式
int i = 0; //下标,用于遍历后缀表达式
while(i <list.size()){
//如果是操作符,就将栈顶头两个出栈,进行计算,将计算后的结果入栈,然后重复操作
if(list.get(i).equals("+") || list.get(i).equals("-") || list.get(i).equals("*") || list.get(i).equals("/")){
double numLastToOne = Double.parseDouble(strStack.pop());
double numLastToTwo = Double.parseDouble(strStack.pop());
double operatorResult = cal(numLastToTwo,numLastToOne,list.get(i).charAt(0));
strStack.push(String.valueOf(operatorResult));
}else{ //如果是数字,入栈,等待计算
strStack.push(list.get(i));
}
i ++;
}
result = strStack.pop();
return result;
}
//简单四则运算
public double cal(double paramsOne,double paramsTwo, char symbol){
double result = 0;
switch (symbol){
case '+':{
result = paramsOne + paramsTwo;
break;
}
case '-':{
result = paramsOne - paramsTwo;
break;
}
case '*':{
result = paramsOne * paramsTwo;
break;
}
case '/':{
result = paramsOne / paramsTwo;
break;
}
}
//结果保留两位有效数字
return Double.parseDouble(String.format("%.2f",result));
}
//检查字符串是否合格
public boolean checkStr(){
String str = this.inputString;
if(!(illegalCharacter(str) || continuousOperator(str) || exceptZero(str) || emptyBrackets(str))){
return true;
}else{
return false;
}
}
//非法字符
public boolean illegalCharacter(String str){
//利用正则判断是否存在,后面一样
String exp = "[^0-9\\.\\+\\*\\-/=\\(\\)]";
Pattern pattern = Pattern.compile(exp);
Matcher matcher = pattern.matcher(str);
if(matcher.find()){
System.out.println("存在非法字符");
return true;
}else{
return false;
}
}
//连续操作符
public boolean continuousOperator(String str){
String exp = "[=\\+\\-\\*/]{2,}";
Pattern pattern = Pattern.compile(exp);
Matcher matcher = pattern.matcher(str);
if(matcher.find()){
System.out.println("存在连续操作符");
return true;
}else{
return false;
}
}
//除0操作
public boolean exceptZero(String str){
String exp = "/0";
Pattern pattern = Pattern.compile(exp);
Matcher matcher = pattern.matcher(str);
if(matcher.find()){
System.out.println("存在除0操作");
return true;
}else{
return false;
}
}
//检查是否有空括号
public boolean emptyBrackets(String str){
String exp = "\\(\\)";
Pattern pattern = Pattern.compile(exp);
Matcher matcher = pattern.matcher(str);
if(matcher.find()){
System.out.println("存在空括号");
return true;
}else{
return false;
}
}
}
计算器的主要编程思想是想办法将中缀表达式转化为后缀表达式,便于计算
写之前可以先去了解一下中转后的思想,事半功倍