사칙연산 구현하기(연산 법칙 지킴)

구창회·2023년 5월 26일
0

자바 공부 중

목록 보기
5/10

프로그래머스 사칙연산 구현 문제 시험을 풀다가 시간이 지나버려서 내가 줄줄이 쓴 코드를 완성하지 못하고 날라가버렸기 때문에...

짜증나서 다시 구현할 겸 (내가 풀 수 있는 문제인지 테스트 겸) 코드를 작성하겠습니다.

사칙연산 구현하기 ( 연산 순서대로 곱하기와 나누기를 먼저 계산하고 그 다음 더하기와 빼기를 합니다 ). 문자열 형태의 연산을 받으면 그것을 계산한 답을 문자열 형태로 리턴합니다. 단 소숫점 둘째자리까지만 표현합니다.(반올림, 올림, 내림 중 '내림' 사용하기)

public class Solution { // 사칙연산 구현하기
    public static void main(String[] args) {
        String s =  "2*3+5/6*3+15";
        s = divideOrMultiply(s);
        s = plusOrMinus(s);
        System.out.println("계산된 수식은..: " + s);
    }

    public static String divideOrMultiply(String string){
        String s = string;

        String left = "";
        String right = "";
        int cur = -1;
        int leftCur = -1; 
        int rightCur = -1;
        char DM = 'a';

        
        while (true) {

            // dm(divide or multiply) 기호위치 찾기
            for (int i = 0; i < s.length(); i++) {
                if (s.charAt(i) == '*' || s.charAt(i) == '/') {
                    cur = i;
                    DM = s.charAt(i);
                    break;
                }
            }
            // 반복문 탈출조건 -> 찾아야하는 기호가 없을때 : cur == -1;
            if (cur == -1) {
                break;
            }
            // left 찾기
            for (int i = cur - 1; i >= 0; i--) {
                if (Character.isDigit(s.charAt(i)) || s.charAt(i) == '.') {
                    left = s.charAt(i) + left;
                } else {
                    leftCur = i;
                    break;
                }
            }
            // right 찾기
            for (int i = cur + 1; i < s.length(); i++) {
                if (Character.isDigit(s.charAt(i)) || s.charAt(i) == '.') {
                    right = right + s.charAt(i);
                } else {
                    rightCur = i;
                    break;
                }
            }
            // 계산 하기
            String replaceAfter = "";

            if (DM == '*') {
                replaceAfter = String.format("%.2f", Double.parseDouble(left) * Double.parseDouble(right));
            } else if (DM == '/') {
                replaceAfter = String.format("%.2f", Double.parseDouble(left) / Double.parseDouble(right));
            }
            // string 에 replace하고 cur, Dm, left, right 초기화 하기
            s = s.substring(0, leftCur + 1) + replaceAfter + s.substring(rightCur);
            cur = -1;
            DM = 'a';
            left = "";
            right = "";
            leftCur = -1;
            rightCur = -1;
        }

        return s;
    }

    public static String plusOrMinus(String string) {
        String s = string;

        String left = "";
        String right = "";
        int cur = -1;
        int leftCur = -1; 
        int rightCur = -1;
        char PM = 'a';

       
        while (true) {

            // pm(plus or minus) 기호위치 찾기
            for (int i = 0; i < s.length(); i++) {
                if (s.charAt(i) == '+' || s.charAt(i) == '-') {
                    cur = i;
                    PM = s.charAt(i);
                    break;
                }
            }
            // 반복문 탈출조건 -> 찾아야하는 기호가 없을때 : cur == -1;
            if (cur == -1) {
                break;
            }
            // left 찾기
            for (int i = cur - 1; i >= 0; i--) {
                if (Character.isDigit(s.charAt(i)) || s.charAt(i) == '.') {
                    left = s.charAt(i) + left;
                } else {
                    leftCur = i;
                    break;
                }
            }
            // right 찾기
            for (int i = cur + 1; i < s.length(); i++) {
                if (Character.isDigit(s.charAt(i)) || s.charAt(i) == '.') {
                    right = right + s.charAt(i);
                } else {
                    rightCur = i;
                    break;
                }
            }
            if (rightCur == - 1) {    // 마지막 계산에서 rightCur 이 -1 이 되는 문제해결
                rightCur = s.length() - 1;
            }

            // 계산 하기
            String replaceAfter = "";

            if (PM == '+') {
                replaceAfter = String.format("%.2f", Double.parseDouble(left) + Double.parseDouble(right));
            } else if (PM == '-') {
                replaceAfter = String.format("%.2f", Double.parseDouble(left) - Double.parseDouble(right));
            }
            // string 에 replace하고 cur, Dm, left, right 초기화 하기
            s = s.substring(0, leftCur + 1) + replaceAfter + s.substring(rightCur);
            cur = -1;
            PM = 'a';
            left = "";
            right = "";
            leftCur = -1;
            rightCur = -1;
        }

        return s;
    }

}

기존코드의 문제점

  • 반복문의 탈출 조건을 체크하지 않았다.
  • 반복문 내에서 사용되는 변수들을 매 반복시에 초기화 하지 않았다.
  • String 의 replaceFirst() 라는 메소드가 내가 원하는대로 동작하지 않았다.
    -- replace() 를 사용하지 않은 이유는, 해당 되는 모든 문자열을 바꿔버리기 때문에 사칙연산에서 사용할 수 없기 때문
    -- 따라서 String 을 잘라붙이는 방법을 사용하였다.
  • left 계산 할때 0.83 인 경우에 83 으로 읽음 (. 이라는 소수점을 파악 못하였다)
  • 찐 마지막 계산, 즉 연산기호가 하나 남은 경우의 연산에서, 연산을 진행 한 뒤에 마지막 substring() 부분에서 rightCur 이 여전히 -1 인 상태여서 생겼던 오류 발견.

깨달은 점

  • 프로그래머스 등 코테를 칠 때, 정말 사용하는 변수 하나하나, 바뀔 때마다 print를 찍었다면 위에서 만난 문제들을 미리 해결할 수 있었지 않았을 까 하는 생각이 든다. 그러지 않고 눈코딩으로 문제점을 파악하려다 보니 절대 파악하기 힘들었다.
  • IntelliJ 에서 코드를 수정하면서 디버깅툴의 도움이 없었다면..ㄷ

해야하는 것

  • divideOrMultiply 함수와 plusOrMinus 함수는 상당히 많은 부분이 같다. 코드를 짠 입장에서 말해보면 동작 방식이 똑같고 적용되는 기호가 곱하기 나누기냐 - 더하기 빼기냐 의 차이 밖에 없다.
  • 그렇다면 위처럼 코드를 짜는 것은 잘못 짜여진 드러운 코드가 아닐까라는 의문이 들면서 어떻게 저 코드들을 아름답게 리팩터링 해볼 수 있을까 라는 고민이 든다.
  • 아마 내 자바공부 인생에서 - 리팩터링(?)이라고 부를 수 있다면 - 첫 리팩터링이 될 것이다.
profile
백엔드 엔지니어 프로 지망생

0개의 댓글