Stack 과 Queue를 배운뒤 괄호가 이것들로 처리된다는 걸 보고

 

문득 이제 계산기를 만들 수 있겠다 싶었다.

 

찾아보니 많은 자료들이 Swing이란 것을 이용한 것 같은데 나는 초보라 알지도 못하고

 

보니 실무에서 많이 안쓰는지 책에도 내용이 개정되어 빠졌다 ㅠㅠ

 

그래서 그냥 처음 내가 생각한대로 구현해보자 마음먹었다.

 

하지만 막상 해보니 1+2 나 숫자 2개를 입력받아 처리는 매우 쉬웠지만 내가 원하는대로 구현은 상당히 어려웠다.

(이상한 집념이 생겨서 이틀이나 날려먹었다....)

게다가 이틀이나 고생했는데 아직도 고쳐야 할 부분이 있다.

(어쩌면 내가 못찾은 문제가 더 있을지도....)

 

기본적으로 구상한것은 이랫다

1. 괄호의 처리

  • Stack을 활용하여 ((((를 push하고 ) 이 처음 pop 되는 순간에 (와 )의 중간 수식을 Middle로 뽑아낸다
  • Middle 수식을 사칙연산에 넣어서 처리 후
  • 새로운 Middle 값을 (Middle)에 전부 대체해 괄호와 이전 수식 제거
  • 또 다시 수행하며 )이 pop 될떄 Middle 다시 처리 반복

2. 뽑아낸 Middle의 처리(이게 난관일줄이야... 갈 길이 멀다)

  • 제일 중요한 것이 문자열을 숫자와 부호로 구분하는 것이였다
  • 한참 고민하고 구글링을 하며 split + 정규표현식 이라는 것을 사용하면 가능하다고 해서 적용했다
String[] numtmp = Middle.split("(?<=[*/+-])|(?=[*/+-])");//정규연산자
  • 위 코드를 적용하면 아마 */+- 인것과 아닌것으로 구분되고 ?는 앞에 전체를 구분해서 잘라내는것 같다
  • 처음에는 정규표현식을 \w(알파벳+숫자) \W(그 반대) 로 써서 뽑아냈는데
  • 구현하고 보니 치명적인 단점이 나눗셈을 위해 반환을 Double로 해놓아서 100.0 같은 ( . ) 이 구분되어 고통받았다
  • 이렇게 구분한 것들을 LinkedList 에 넣고 숫자와 부호로 나누고
  • 부호의 갯수를 count 해서 이때 곱하기+나누기의 횟수 를 저장 후 count만큼 곱하기 나누기를 먼저 수행하도록 함

코드를 작성한 후 돌려보니 먼가 흐뭇하게 돌아가서 잠시 기뻣다 ㅎㅎ

하지만 돌리다보니 오류가 나는 점이 발견되고 스스로도 에러라 생각되는 점도 생각하게 됐다.

  1. '(' 과 ')' 의 갯수가 서로 일치하지 않을때의 Exception 필요
  2. -5*2 와 같은 음수로 시작하는 Middle
  3. 2*-5 와 같이 음수로 끝나는 수식이 포함된 Middle (아직 수정못했다... ㅠㅠ)

1 의 에러는 Exception 만 적절히 해주면 해결되서 다행이였지만

2 와 3의 에러는 골치가 아팠다.

기본적으로 음수도 적용되는 계산기라면 저것들은 오류라기보단 뭔가 코드를 수정해야하는 결함에 가까운것 같다.

그래서 고민끝 해결책으로 

2의 경우는 0-5*2 와 동일한 수식이라는 점을 해결책으로 찾았다

 

3의 경우도 뭔가 해결책을 찾아야하는데... 이틀 고민했더니 다른 공부가 너무 밀려버려서 

이제 그만하고 생산적인 일을 해야하지 않을까 하는 생각(=변명 ㅎㅎ) 이 들어서 

나중에 초보를 벗어나면 다시 더 간결한 코드로 새로짜야겠다 생각했다.

 

간단한 계산기 구현이였는데도 내가 짠 코드를 내가 헷갈릴 정도로 어지러워졌고 코드가 너무 조잡한거같다.

 

그래도 덕분에 객체 지향이라는게 얼마나 편리한지 

그리고 String 이나 배열 보다 StringBuffuer, LinkedList가 사용면에서 얼마나 더 편리한지 몸소 느끼게 됐다.

 

아직 초보도 진입을 못했구나 하는 나의 현실을 여실히 느끼며 다시 공부에 전념해야겠다.

 

<아직 미해결 문제점  : 곱하기와 나누기 뒤에 음수면 에러>

import java.util.EmptyStackException;
import java.util.LinkedList;
import java.util.Stack;

//고쳐야 할 점 : 음수를 뒤에서 곱하거나 나누면 에러!!!!!
public class make_calcul_2st {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyCaluCulLator SWver1 = new MyCaluCulLator();
		StringBuffer input = new StringBuffer("(-2*3+2-2*3-3+7-6*7)*4/(3+2)+3/2-5");
			try {
				System.out.println("노력의 결실이 나옵니다!!!! 답은?"+SWver1.RG(input));
			} catch (EmptyStackException | MyCaluCulLator.OverStackException e) {
				System.out.println("괄호가 맞지 않습니다");
			} 
	}
}
/*
 * 필요사항
 * 1. 괄호 계산이 1순위
 * 2. *와 / 우선순위
 * 3. -A & B 계산시 동시처리
 * => 숫자를 쌓기엔 어레이리스트
 * => 부호를 찾기엔 스택? 문제는 찾으면 날라감
 * =>
 */
class MyCaluCulLator{
	String input;
	MyCaluCulLator(){}
	MyCaluCulLator(String input){
		this.input = input ;
	}
//-----------------------------------생성자 초기화-----------------------------------
//-------------------------------------괄호 없는 경우 String 수식의 계산------------------------
	public String RealCalCul(String Middle) {
		System.out.println("-----------------수식"+Middle+"--------------------");
		String result="";
		String[] numtmp = Middle.split("(?<=[*/+-])|(?=[*/+-])");//정규연산자
		boolean nobuho =true;
		for (int i = 0; i < numtmp.length; i++) {
			if(isbuho(numtmp[i])) {
				System.out.println("부호가 있네요");
				nobuho = false;
				break;
			}
		}
		if(nobuho){ return Middle; }
		
		LinkedList<String> num = new LinkedList<>();
		LinkedList<String> buho = new LinkedList<>();
		int multidivi_count=0;
		int minus = 0;
		for(String a: numtmp) {
			if(isbuho(a)) {
				buho.add(a);
				if(a.equals("*")||a.equals("/")) multidivi_count++;
				else if(a.equals("-")) minus++;
			}
			else {
				num.add(a);
			}
		}
		int plmicount = buho.size() - multidivi_count - minus;
		System.out.println(multidivi_count+"번 곱셈나눗셈 수행할게요");
		//부호와 숫자 분리 완료
		//곱하기 나누기 횟수 저장 후 양수면 먼저수행
		if(multidivi_count>0||plmicount>0) {
			while(multidivi_count!=0) {
				int index = buho.indexOf("*");
				System.out.println(index);
				if(index>=0) {
					System.out.println("곱하기 수행");
					String a = ""+TheCal(num.get(index),"*",num.get(index+1));
					num.remove(index);
					num.remove(index);
					num.add(index, a);
					buho.remove(index);
					System.out.println(num.get(index));
					multidivi_count--;
				}
				int index2 = buho.indexOf("/");
				System.out.println(index2+"=index2값");
				if(index2>=0) {
					System.out.println(num.get(index2));
					System.out.println("나누기 수행");
					String ac = ""+TheCal(num.get(index2),"/",num.get(index2+1));
					num.remove(index2);
					num.remove(index2);
					num.add(index2, ac);
					buho.remove(index2);
					System.out.println(num.get(index2));
					multidivi_count--;
					}
				}//곱하기 while끝
			//곱하기 나누기 완료
		
		//더하기 수행
			System.out.println("현재값");
			for(String a: num) {
				System.out.println(a);
			}
			for(String a: buho) {
				System.out.println(a);
			}
			
		while(minus!=0) {
			int index4 = buho.indexOf("-");
			if(index4>=0) {
				System.out.println(num.get(index4));
				System.out.println("빼기 수행");
				String ab = ""+TheCal(num.get(index4),"-",num.get(index4+1));
				num.remove(index4);
				num.remove(index4);
				num.add(index4, ab);
				buho.remove(index4);
				System.out.println(num.get(index4));
				minus--;
			}
		}
		while(plmicount!=0) {
			int index3 = buho.indexOf("+");
			if(index3>=0) {
				System.out.println(num.get(index3));
				System.out.println("더하기 수행");
				String a = ""+TheCal(num.get(index3),"+",num.get(index3+1));
				num.remove(index3);
				num.remove(index3);
				num.add(index3, a);
				buho.remove(index3);
				System.out.println(num.get(index3));
				plmicount--;
			}
		}
		}
			
		
		System.out.println("결과는!!!!!!"+num.get(0));
		
		Middle = num.get(0);
		return Middle;
	}
	
	

/*-----------------------------수식에 괄호가 있는 경우 추출 메서드----------------------------*/
	public String RG(StringBuffer input2) 
			throws  MyCaluCulLator.OverStackException {
				Stack st = new Stack(); //괄호 쌍 검사용 임시 스택
				int startindex=0;
				int endindex=0;
				int count = 0;
				int count1 = 0;
			for (int i = 0; i < input2.length(); i++){
					if((input2.charAt(i)=='(')){
							st.push('(');
							count1++;
							startindex=i;
													}//end
					
					else if (input2.charAt(i)==')') {
							st.pop();
							count1--;
							endindex=i;
							String middle =input2.substring(startindex+1, endindex);
							System.out.println("이번 괄호는 "+middle+"입니다");
							char[] c = middle.toCharArray();
							for (int j = 0; j < c.length; j++) {
								boolean minor = isbuho(c[j]+"");
								if(j==0&&minor){
									middle = "0"+middle;
									System.out.println("음수감지 0추가"+middle);
									}
								}
							middle = RealCalCul(middle);
	
							c = middle.toCharArray();
							for (int j = 0; j < c.length; j++) {
								boolean minor = isbuho(c[j]+"");
								if(j==0&&minor){
									middle = "0"+middle;
									System.out.println("음수감지 0추가"+middle);
									}
								}
						input2 =input2.replace(startindex, endindex+1,middle);
						RG(input2);
						break;
						}//end
						}
						String input3 = input2.toString();
		if(count1==0) {		
		char[] c= input3.toCharArray();
		for (int j = 0; j < c.length; j++) {
			boolean minor = isbuho(c[j]+"");
			if(minor){
				count++;
			}
		}
		System.out.println("마지막 남은 부호 처리구간, 부호 갯수:"+count);
		System.out.println(input3);
		if(count!=0) {
			input3 = RealCalCul(input3);
		}
		
		}
		return input3;
		
}
	
	
	
/*---------------------------String A&B의 계산 메서드---------------------------*/
	public double TheCal(String A , String b, String B) {
		double a = Double.valueOf(A);
		double c = Double.valueOf(B);
		double result=0;
		switch(b) {
		case "+" : result = sum(a,c); break;
		case "-" : result =sub(a,c);break;
		case "/" : result =divide(a,c);break;
		case "*" : result =multi(a,c);break;
		}
		double per = Double.parseDouble(String.format("%.4f",result));
		return per;
		
	}
/*--------------------------연산자 문자인지 확인 BOOLEAN------------------------*/
	public boolean isbuho(String d) {
			if(d.equals("+")) 		return true;
		else if(d.equals("-")) return true;
		else if(d.equals("/")) return true;
		else if(d.equals("*")) return true;
		else return false;
	}
/*-------------------------기본 4칙연산-------------------------------------*/
	public double sum(double a, double b) {
		return a+b;
	}
	public double sub(double a, double b) {
		return a-b;
	}
	public double multi(double a, double b) {
		return a*b;
	}
	public double divide(double a, double b) {
		return a/b;
	}
/*-------------------------괄호 남는 예외-------------------------------------------*/
	class OverStackException extends Exception{
		OverStackException(String msg){
			super(msg);
		}
	}

}

 

 

'개발자로 업그레이드 되자 > JAVA' 카테고리의 다른 글

JAVA의 IO  (0) 2021.10.24
JAVA 컬렉션(Collection)  (0) 2021.10.05
Java의 기본 개념들을 정리  (0) 2021.09.12
JAVA 별 만들기 코드  (0) 2021.08.15

+ Recent posts