본문 바로가기
Project/Java

[Java Project] 공학용 계산기 & 후위식 계산

by 꾸압 2022. 2. 7.

javascript 로 짜기 전에 만든 java version의 공학용 계산기다.

본래 jsp 파일을 view 로 만들고, java에서 controller&service&dto 등 mvc 패턴을 적용하여 만들려고 하였으나...

피드백 주신 사수 분이 javascript 를 배워야한다고 말씀하시어... 중간에 유기된 프로젝트... 미안하다...

 

괄호에 대한 사칙연산의 후위식 계산을 포함하며, 삼각함수-괄호에 대한 오류 처리 등 세부 기능은 전무하다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;

import org.springframework.stereotype.Controller;

@Controller
public class MainController {

	public static void main(String[] args) throws IOException{
		
		// BufferedReader 로 문자열을 자유롭게 삽입
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		String input = br.readLine();
		
		br.close();
		
		// StringTokenizer을 통해 공백에 따라 문자열 자르기
		StringTokenizer str = new StringTokenizer(input, " ");
		System.out.println("(1) 입력값 stringtokenizer : " + str + "\n");
		
		
		// 각 요소 삽입을 위한 배열 생성
		List<String> arr = new ArrayList<String>();
		
		
		// 저장 배열
		ArrayList<String> arrSplit = new ArrayList<>();
		// 연산자 stack
		Stack<String> stackOp = new Stack<>();
		// 계산 stack
		Stack<String> stackCal = new Stack<>();
		
		// 공백이 없을 때 까지 배열에 넣기 반복
		while(str.hasMoreElements()) {
			
			arr.add(str.nextToken());
		}
		System.out.println("(2) arr 배열값 : " + arr + "\n");
		
		
		// stack 에서 arr로 넘어간 후로 error 발생
		// 괄호 이후에 * 이 안 넘어감
		for(int i=0; i < arr.size(); i++) {
			
			classifi(arr, arrSplit, i, stackOp);
			System.out.println("[classifi " + i + "]" + arrSplit);
			System.out.println("[classifi " + i + "]" + stackOp);
			
			if(arr.get(i).equals(")")) {
				
				int j = 0;
				
				// stackOp to arrSplit 연산자 이동
				stackToArr(arr, arrSplit, j, stackOp);

				System.out.println("\n" + "[stack >>> " + "]" + stackOp);
				System.out.println("[>>> Arr " + "]" + arrSplit + "\n");
			}
		}
		System.out.println("(3-1) arrSplit 배열 : " + arrSplit);
		System.out.println("      stackOp 스택  : " + stackOp + "\n");
		
		// 계산식 parsing 완료 후 stack의 모든 연산자를 배열에 저장
		while(true) {
			
			for(int i=0; i < stackOp.size(); i++) {
				
				arrSplit.add(stackOp.get(stackOp.size() - 1));
				stackOp.pop();
			}
			if(stackOp.isEmpty()) {
				break;
			}
		}
		
		
		System.out.println("(3-2) arrSplit 배열 : " + arrSplit);
		System.out.println("      stackOp 스택  : " + stackOp + "\n");
		
		
		// 후위식 배열에서 순서대로 숫자를 꺼내, 연산자가 나올 때까지 stackCal에 저장
		moveCal(arrSplit, stackCal);
		System.out.println("(3-3) arrSplit 배열 : " + arrSplit);
		System.out.println("      stackCal 스택  : " + stackCal + "\n");
		
		
		// 계산 값을 옮기는 가운데 임시 저장 목적의 메신져 변수 result. 
		int result = 0;
		String rst = "";
		
		// distinction(arrSplit)
		// arrSplit 과 stackCal 사이의 계산
		while(true) {
						
			// arrSplit 배열의 index(0) 이 연산자면 stackCal 의 요소와 
			// 연동하여 계산 후, stackCal 에 add 한다.
			if (distinction(arrSplit)) {
				
				// stackCal 의 마지막 요소 및 끝에서 2번째 요소를 빼내고, 계산하기 위해
				// int 로 type 변환
				int numSec = Integer.parseInt(stackCal.get(stackCal.size() - 1));
				stackCal.pop();
				int numFir = Integer.parseInt(stackCal.get(stackCal.size() - 1));
				stackCal.pop();

				switch (arrSplit.get(0)) {
				case "+":
					result = numFir + numSec;
					arrSplit.remove(0);
					break;
				case "-":
					result = numFir - numSec;
					arrSplit.remove(0);
					break;
				case "*":
					result = numFir * numSec;
					arrSplit.remove(0);
					break;
				case "/":
					result = numFir / numSec;
					arrSplit.remove(0);
					break;
				}

				// stackCal에 저장하기 위해 계산 결과인 rst를 String을 type 변환
				rst = Integer.toString(result);

				// 결과 값을 stackCal에 add
				stackCal.add(rst);
				
				if(arrSplit.isEmpty()) {
					stackCal.pop();
					break;
				}
			}
			
			// arrSplit 배열에 숫자가 남아 있을 경우 stackCal 에 값을 넘겨 계산 진행
			else if(!distinction(arrSplit)) {
				
				stackCal.add(arrSplit.get(0));
				arrSplit.remove(0);
			}
		}
		
		// 결과값 출력
		System.out.println(rst);
	}
	
	
	// 연산자 및 숫자 저장 분배 함수
	public static void classifi(List<String> arr, 
				ArrayList<String> arrSplit, int i, 
				Stack<String> stackOp) {
		
		if(arr.get(i).equals("+") || arr.get(i).equals("-")) {
			
			// 이전 string이 ')' 괄호 였을 경우, 연산자 우선 순위 비교에 따라 arr 또는 stack에 값을 넣음
			if(arr.get(i-1).equals(")")) {
				
				arrSplit.add(stackOp.get(stackOp.size() - 1));
				stackOp.pop();
				stackOp.add(arr.get(i));
			}
			// 이전 string이 괄호가 아닌 경우, 그냥 arr에 넣음
			else {
				
				stackOp.add((String) arr.get(i));
			}
		}
		else if(arr.get(i).equals("*")) {
			
			stackOp.add((String) arr.get(i));
		}
		else if(arr.get(i).equals("/")) {
			
			stackOp.add((String) arr.get(i));
		} 
		else if (arr.get(i).equals("(")) {

			stackOp.add((String) arr.get(i));
		}
		// else 에 포함시키지 않으며 동시에 ')' 를 넣지 않기 위한 조건
		else if (arr.get(i).equals(")")) {

			
		}
		else {
			arrSplit.add((String) arr.get(i));
		}
	}
	
	public static void stackToArr(List<String> arr, 
			ArrayList<String> arrSplit, int j, 
			Stack<String> stackOp) {

		while (true) {

			// stack 요소가 '(' 라면 배열로의 이동을 중단하고, 괄호를 제거
			if(stackOp.get(j).equals("(")) {
				
				stackOp.pop();
				break;
			}
			else {
				// stack 요소가 ')' 이 아니라면 마지막 값을 arrSplit 배열로 이동 후 pop
				if(!stackOp.get(j).equals(")")) {
					
					arrSplit.add(stackOp.get(stackOp.size() - 1));
					stackOp.pop();
				}
				// stack 요소가 ')' 라면 괄호를 제거
				else if(stackOp.get(j).equals(")")) {
					
					stackOp.pop();
				}
			}
			// while 증가용 변수 'j'
			j++;
		}

	}
	
	// 후위식 배열에서 순서대로 숫자를 꺼내, 연산자가 나올 때까지 stackCal에 저장
	public static void moveCal(ArrayList<String> arrSplit, Stack<String> stackCal) {
	
		while(true) {
		
			if(arrSplit.get(0).equals("+")) {
			
				break;
			}
			else if(arrSplit.get(0).equals("-")) {
			
				break;
			}
			else if(arrSplit.get(0).equals("*")) {
			
				break;
			}
			else if(arrSplit.get(0).equals("/")) {
			
				break;
			} 
			else {
				stackCal.add(arrSplit.get(0));
				arrSplit.remove(0);
			}
		}
	}
	
	// distinction : 배열값이 문자열인지 숫자인지 구분하는 메소드
	public static boolean distinction(ArrayList<String> arrSplit) {
		
		if(arrSplit.get(0).equals("+")) {
			
			return true;
		}
		else if(arrSplit.get(0).equals("-")) {
		
			return true;
		}
		else if(arrSplit.get(0).equals("*")) {
		
			return true;
		}
		else if(arrSplit.get(0).equals("/")) {
		
			return true;
		} 
		else {
			return false;
		}
	}
}

 

 

 

 

 

 

 

댓글