프로그래머스 신규 아이디 추천 [Java]

문제출처

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

 

코딩테스트 연습 - 신규 아이디 추천

카카오에 입사한 신입 개발자 네오는 "카카오계정개발팀"에 배치되어, 카카오 서비스에 가입하는 유저들의 아이디를 생성하는 업무를 담당하게 되었습니다. "네오"에게 주어진 첫 업무는 새로

programmers.co.kr

처음에 문제를 보면서 완전 거저주는 문제라고 생각했는데 채점 결과 틀린 케이스가 6개인가? 있었다.

class Solution {
    public String solution(String new_id) {
        String answer = "";
        
        //1단계
        new_id = new_id.toLowerCase();
        //2단계
        new_id = new_id.replaceAll("[~!@#$%^&*()=+[{]};?,<>/]", "");
        //3단계
        for(int i = 0; i < new_id.length(); i++){
            if(new_id.charAt(i) == '.'){
                while(i < new_id.length() - 1 && new_id.charAt(i+1) == '.'){
                    new_id = new_id.substring(0, i) + new_id.substring(i + 1);
                }
            }
        }
        //4단계
        if(new_id.charAt(0) == '.'){
            new_id = new_id.substring(1);
        }
        if(new_id.length() > 0&& new_id.charAt(new_id.length() - 1) == '.'){
			new_id = new_id.substring(0, new_id.length() - 1);
        }
        //5단계
        if(new_id.length() == 0){
        	new_id = "a";
    	}
        //6단계
        if(new_id.length() > 15){
            new_id = new_id.substring(0, 15);
		} 
        if(new_id.charAt(new_id.length() - 1) == '.'){
        	new_id = new_id.substring(0, new_id.length() - 1);
    	}
        //7단계
        while(new_id.length() <= 2 ){
            new_id = new_id + new_id.substring(new_id.length() - 1);
        }
        
        answer = new_id;
   
        return answer;
	}
}

틀린 코드인데 아무리 생각해도 반례가 생각이 나지 않았는데 허무하게도 2단계의 정규표현식이 틀렸다.

 

만약 실제로 테스트 중이었다면 절대 고치지 못 했을 것이다... 그래서 이 기회에 정규표현식을 정리해봤다.

글 링크 : 

https://lastday9.tistory.com/92

 

[자바/Java] 정규표현식

정규표현식(regex)는 일정한 패턴을 표현하는 일종의 형식 언어이다. 주민번호, 차량번호, 전화번호 같이 어떤 일정한 모양새가 있는 곳에 사용하면 개발시에 편리하게 쓸 수 있고 자바 외에도 파

lastday9.tistory.com

 

이렇게 제출하니 바로 맞혔다.

class Solution {
    public String solution(String new_id) {
        String answer = "";
        
        //1단계
        new_id = new_id.toLowerCase();
        //2단계
        new_id = new_id.replaceAll("[^-_.a-z0-9]", "");
        //3단계
        for(int i = 0; i < new_id.length(); i++){
            if(new_id.charAt(i) == '.'){
                while(i < new_id.length() - 1 && new_id.charAt(i+1) == '.'){
                    new_id = new_id.substring(0, i) + new_id.substring(i + 1);
                }
            }
        }
        //4단계
        if(new_id.charAt(0) == '.'){
            new_id = new_id.substring(1);
        }
        if(new_id.length() > 0&& new_id.charAt(new_id.length() - 1) == '.'){
                new_id = new_id.substring(0, new_id.length() - 1);
        }
        //5단계
        if(new_id.length() == 0){
            new_id = "a";
        }
        //6단계
        if(new_id.length() > 15){
            new_id = new_id.substring(0, 15);
            if(new_id.charAt(new_id.length() - 1) == '.'){
                new_id = new_id.substring(0, new_id.length() - 1);
            }     
        }
        //7단계
        while(new_id.length() <= 2 ){
            new_id = new_id + new_id.substring(new_id.length() - 1);
        }

        answer = new_id;
                  
        return answer;
    }
}

이 문제는 kakao 블라인드 코테 문제던데 전에도 그렇고 문자열을 잘 다루는 문제가 많이 나오는거 같다...

 

2단계는 영어소문자, 숫자, -, _, .을 제외하고는 삭제를 해야하는 단계이다.

내가 처음에 적은 정규식은 이거

"[~!@#$%^&*()=+[{]};?,<>/]"

정답은 이거

"[^-_.a-z0-9]"

깔끔하게 -_.과 영어, 숫자가 아닌 것을 표현했는데 첫번째거의 경우 대괄호를 찾거나 할때 앞에 역슬래시가 없다. 역슬래시가 없으면 정규표현식의 규칙으로 인식 해버린다.

역슬래시를 2개 넣어줘야지 정상적으로 인식한다. 첫번째거를 올바르게 쓰고 싶었다면 역슬래시 때문에 몹시 길어졌을거 같다.

 

2단계에서만 정규식을 쓸 생각을 했는데 다른 사람들의 정답을 보니 이 문제 전체를 정규표현식으로 풀 수 있어서 다시 한번 정규식으로 풀어보았다. 훨씬 간결해졌다...

class Solution {
    public String solution(String new_id) {
        String answer = "";
        
        //1단계
        new_id = new_id.toLowerCase();
        //2단계
        new_id = new_id.replaceAll("[^-_.a-z0-9]", "");
        //3단계
        new_id = new_id.replaceAll("[.]{2,}", ".");
        //4단계
        new_id = new_id.replaceAll("^[.]|[.]$", "");
        //5단계
        if(new_id.length() == 0){
            new_id = "a";
        }
        //6단계
        if(new_id.length() > 15){
            new_id = new_id.substring(0, 15);
            new_id = new_id.replaceAll("[.]$", "");    
        }
        //7단계
        while(new_id.length() <= 2 ){
            new_id = new_id + new_id.substring(new_id.length() - 1);
        }

        answer = new_id;
                  
        return answer;
    }
}

 

마지막으로 substring이 아주 헷갈려서 상당히 고생했기 때문에 문자열 관련 메소드들을 정리하고 마치겠다.

 

-문자열.toUpperCase() : 문자열을 대문자로 바꿔줌

-문자열.toLowerCase() : 문자열을 소문자로 바꿔줌

 

-문자열.replaceAll(a, b) : 문자열의 a들을 b로 바꿔줌

.replace()와의 차이 replace는 a인자가 문자열인데 replaceAll은 a인자에 정규식을 넣을 수 있다.

 

-문자열.length() : 문자열의 길이를 반환

ex) "abc1de2" 는 문자열의 길이가 7이다.

 

-문자열.substring(n) : n번째 인덱스부터 문자열의 끝까지 슬라이싱한다.

ex) 

String str = "abc1de2";
str = str.subString(5);

이렇게 되면 str은 "e2"가 된다.

 

-문자열.subString(n1, n2) : n1번째 인덱스부터 n2 - 1번째 문자열까지 슬라이싱한다.

ex)

String str = "abc1de2";
str = str.subString(4,str.length() - 1);

이 경우에는 str은 "de2"가된다.

 

-문자열.charAt(n) : 문자열의 인덱스가 n인 자리에 있는 문자 한글자를 반환한다. char타입으로 반환됨.

myoskin