링크

https://school.programmers.co.kr/learn/courses/30/lessons/72410

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제

 

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
     만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.

 

풀이

 

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
     만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.

위의 내용을 하나씩 적용합니다.

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();
       
        return new_id;
}

 

toLowerCase 함수는 모든 대문자를 대응되는 소문자로 치환해주는 함수입니다.
new_id에 toLowerCase 함수를 사용하여 모든 대문자를 대응되는 소문자로 치환해줍니다.

 

2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.

public String emptyWord(String str) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (47 < c && c < 58) {
                sb.append(c);
                continue;
            }
            if (96 < c && c < 123) {
                sb.append(c);
                continue;
            }
            if ('-' == c || '_' == c || '.' == c) {
                sb.append(c);
                continue;
            }
        }
        return sb.toString();
}

알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
필자는 replace, replaceAll 함수로 특정 문자를 제거하는 것이 아닌
반복문을 사용하여 조건에 해당하는 것만 선별 후 리턴하였습니다.
아스키코드 48 ~ 57은 0~9에 해당하는 값입니다.
아스키코드 97 ~ 122는 알파벳 소문자 a~z에 해당하는 값입니다.
그리고 빼기(-), 밑줄(_), 마침표(.)는 각 char형으로 비교하였습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        return new_id;
}

 

3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.

public String closeCheck(String str) {
        StringBuffer sb = new StringBuffer();
        boolean flag = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if ('.' == c) {
                if (flag) {
                    continue;
                }
                sb.append(c);
                flag = true;
                continue;
            }
            sb.append(c);
            flag = false;
        }
        return sb.toString();
}

반복문을 사용했습니다.
마침표(.)가 나왔을 때는 flag = true 로 설정하여 바로 다음 문자가 마침표(.)일 경우 
문자를 담지 않고 현재 반복문을 종료 후 다음 반복문을 수행했습니다.
마침표(.) 외의 문자가 나왔을 때는 flag = false로 설정하고
문자를 담은 후 현재 반복문을 종료하고 다음 반복문을 수행했습니다.
결과적으로 마침표(.)가 중복되서 나오는 경우는 최초 1회만 담게 되고
나머지 문자들은 손실 없이 그대로 담기게 됩니다.

ex)  aa...bb  ->  aa.bb 

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        return new_id;
}

 

4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.

public String startEndCheck(String str) {
        if (str.startsWith(".")) {
            str = str.substring(1);
        }
        if (str.endsWith(".")) {
            str = str.substring(0, str.length()-1);
        }
        return str;
}

startWith, endsWith 함수를 사용하여 처음이나 끝에 마침표(.)가 있다면 
substring을 이용하여 해당 위치의 문자를 잘라내었습니다.

ex)
String str = ".aaaa.";
str = str.substring(1); // "aaaa."
str = str.substring(0, str.length()-1); //"aaaa"

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        return new_id;
}

 

5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.

new_id = ("".equals(new_id)) ? "a" : new_id;

필자는 삼항연산자를 이용하여 new_id가 빈 문자열이라면 "a"를 대입하고 아니라면 new_id를 그대로 사용하였습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        return new_id;
}

 

6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.

new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

new_id = startEndCheck(new_id);

new_id의 길이가 16자 이상이라면, new_id 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거하는 부분은
삼항연산자로 처리하였습니다.
그리고 만약 제거 후 마침표(.)가 new_id의 끝에 위치했을 때 제거하는 기능은
4단계에서 만들어 놓은 startEndCheck(); 함수를 사용하였습니다.
마침표를 제거한다 라는 역할과 책임을 분리하여 기능을 만들었기 때문에 재사용이 가능했습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        //6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
        new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

        //만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
        new_id = startEndCheck(new_id);

        return new_id;
}

 

7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.

public String treeWordCheck(String str) {
        if (str.length() > 2) return str;

        str = str + str.substring(str.length()-1);

        return (str.length() > 2) ? str : str + str.substring(str.length()-1);
}

new_id 길이가 3이 될 때까지가 조건이니 길이 3이상인 문자는 바로 리턴했습니다.
길이 3이상이 아닌 문자의 경우 마지막 글자를 더한 후
다시 길이가 3이상인 문자인지 체크하였고
3이 아니면 마지막 글자를 다시 더한 후 리턴했습니다.

ex)
1. 길이가 3 이상인 경우
바로 리턴.

2. 길이가 2인 경우
"ab" -> 마지막 글자 더하기 -> "abb" -> 길이가 3이상 -> 리턴

3. 길이가 1인 경우
"a" -> 마지막 글자 더하기 -> "aa" -> 마지막 글자 더하기 -> "aaa" -> 길이가 3이상 -> 리턴

4. 길이가 0인 경우
없음 (해당 단계는 7단계입니다. 빈 문자열의 경우 5단계에서 "a"로 치환해줍니다.)

마지막 글자를 더해야 하는 경우는 길이가 1이나 2의 경우입니다.
반복문을 사용하여 처리해도 되지만
최대 2회까지만 마지막 글자를 더해주면 돼서
복잡하게 반복문을 사용하지 않고 처리하였습니다.

public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        //6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
        new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

        //만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
        new_id = startEndCheck(new_id);

        //7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.
        new_id = treeWordCheck(new_id);

        return new_id;
}

 

전체 코드

    public String emptyWord(String str) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (47 < c && c < 58) {
                sb.append(c);
                continue;
            }
            if (96 < c && c < 123) {
                sb.append(c);
                continue;
            }
            if ('-' == c || '_' == c || '.' == c) {
                sb.append(c);
                continue;
            }
        }
        return sb.toString();
    }

    public String closeCheck(String str) {
        StringBuffer sb = new StringBuffer();
        boolean flag = false;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if ('.' == c) {
                if (flag) {
                    continue;
                }
                sb.append(c);
                flag = true;
                continue;
            }
            sb.append(c);
            flag = false;
        }
        return sb.toString();
    }

    public String startEndCheck(String str) {
        if (str.startsWith(".")) {
            str = str.substring(1);
        }
        if (str.endsWith(".")) {
            str = str.substring(0, str.length()-1);
        }
        return str;
    }

    public String treeWordCheck(String str) {
        if (str.length() > 2) return str;

        str = str + str.substring(str.length()-1);

        return (str.length() > 2) ? str : str + str.substring(str.length()-1);
    }

    public String solution(String new_id) {

        //1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
        new_id = new_id.toLowerCase();

        //2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
        new_id = emptyWord(new_id);

        //3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
        new_id = closeCheck(new_id);

        //4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
        new_id = startEndCheck(new_id);

        //5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
        new_id = ("".equals(new_id)) ? "a" : new_id;

        //6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
        new_id = (new_id.length() >= 16) ? new_id.substring(0, 15) : new_id;

        //만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
        new_id = startEndCheck(new_id);

        //7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.
        new_id = treeWordCheck(new_id);

        return new_id;
    }

 

실행결과

 

후기

* 난이도 (5점 만점)

5 : 풀 줄 알면 기업 코딩 테스트는 문제없음.

4 : 평균적인 기업 코딩 테스트의 중간 이상.

3 : 평균적인 기업 코딩테스트의 쉬운 문제.

2 : 알고리즘 문제를 연습하고 있다면 풀 수 있는 문제.

1 : 시간이 오래 걸리지 않고, 누구나 풀 수 있는 문제.

 

정답률 57.50% 에 비해 문제가 어렵지 않았다.
이미 문제에서 1~7단계 설명으로 답을 해설해주었기 때문에 쉽게 풀 수 있었다.
단계별로 하나씩 적용하면 코딩테스트 입문자도 풀 수 있는 문제입니다.
감사합니다.

+ Recent posts