알고리즘/Java

Programmers: 신규 아이디 추천(2021 KAKAO BLIND RECURITMENT)

두넌 2023. 10. 17.

문제 정보


 

프로그래머스

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

programmers.co.kr

 

 

핵심


String / StringBuilder 의 문자열 가공 메서드를 잘 인지하고 있는지!

Regular Expression에 대해서도 어느정도 알아야 효율적으로 풀 수 있는 문제 (replaceAll)

 

풀이


class Solution {
    public String solution(String new_id) {
        String step1 = new_id.toLowerCase();
        
        StringBuilder step2 = new StringBuilder();
        for(int i=0; i<step1.length(); i++) {
            char c = step1.charAt(i);
            if(Character.isLowerCase(c) || Character.isDigit(c) || c == '-' || c == '_' || c == '.' ) {
                step2.append(c);
            }
        }
        String step3 = step2.toString().replaceAll("[.]+", ".");
    	
        StringBuilder step4 = new StringBuilder(step3);
        if(step4.length() > 0 && step4.charAt(0) == '.')
            step4.deleteCharAt(0);
        if(step4.length() > 0 && step4.charAt(step4.length()-1) == '.')
            step4.deleteCharAt(step4.length()-1);
        
        StringBuilder step5 = (step4.length() > 0) ? step4 : step4.append("a");
        
        StringBuilder step6 = step5;
        if(step6.length() >= 16)
            step6.setLength(15);
        if(step6.length() > 0 && step6.charAt(step6.length()-1) == '.')
            step6.deleteCharAt(step6.length()-1);
        
        StringBuilder step7 = step6;
        int lastIndex = step7.length() - 1;
        while(step7.length() <= 2) {
            step7.append(step7.charAt(lastIndex));
        }
        
        return step7.toString();
    }
    
    public boolean isValidId(String id) {
        // Check case 1
        if(id.length() < 3 || id.length() > 15) {
            return false;
        }
        // Check case 2
        for(int i=0; i<id.length(); i++) {
            char c = id.charAt(i);
            if(!(Character.isLowerCase(c) || Character.isDigit(c) || c == '-' || c == '_' || c == '.' )) {
                return false;
            }
        }
        System.out.println("test");
        // Check case 3
        if(id.indexOf(0) == '.' || id.indexOf(id.length()-1) == '.')
            return false;
        int countEndCharacter = 0;
        for(int i=0; i<id.length(); i++) {
            char c = id.charAt(i);
            if(c == '.')
                countEndCharacter++;
            else
                countEndCharacter = 0;
            if(countEndCharacter == 2)
                return false;
        }
        return true;
    }
}

-> 너무 장황하게 작성한 코드인것 같다

가장 첫번째 잘못된 점은, isValidId() 라는 문제에서 요구하는 유효한 아이디인지 확인하는 규칙이 적용되었는지 판단하는 메서드를 작성했는데 실제로 제출할 때에는 이를 적용하지 않았으나 통과했다

하지만 이는 사실상 먼저 확인하면 효율적이긴 하겠지만 규칙이 적용되지 않은 테스트케이스가 많은 경우에는 굳이 확인해주지 않고 고쳐도 되기 때문에 불필요했던 메서드인것 같다

괜히 코드의 길이만 길어지는 ,,,,, 만일 적용한다면 다음과 같이 적용하면 되지 않을까 싶다

if(isValidId(new_id))
	return new_id;

 

또한 StringBuilder / String 의 문자열 처리 메서드를 잘 인지하고 있지 못했던 것 같다

StringBuilder step2 = new StringBuilder();
for(int i=0; i<step1.length(); i++) {
  char c = step1.charAt(i);
  if(Character.isLowerCase(c) || Character.isDigit(c) || c == '-' || c == '_' || c == '.' ) {
    step2.append(c);
  }
}

이렇게 작성한 코드를

s = s.replaceAll("[^a-z0-9._-]", "");

다음과 같은 String의 replaceAll() 메서드와 Regular Expression 를 활용하여 한 줄의 코드로 작성할 수 있었다

 

문자열의 처음과 끝에 마침표(".") 가 존재하면 이를 삭제하는 코드를 다음과 같이 작성하였지만

if(step4.length() > 0 && step4.charAt(0) == '.')
     step4.deleteCharAt(0);
if(step4.length() > 0 && step4.charAt(step4.length()-1) == '.')
     step4.deleteCharAt(step4.length()-1);
s = s.replaceAll("^[.]|[.]$", "");

이러한 간단한 Regular Expression으로 처리 가능했다

 

그리고 자잘하게

StringBuilder step5 = (step4.length() > 0) ? step4 : step4.append("a");

문자열이 비어있는 지 확인하고, 비어있다면 "a"를 추가하는 알고리즘에서도

s = s.isEmpty() ? "a" : s;

사실 이를 기본적으로 비어있는지 확인해 주는 isEmpty() 를 사용하면 되지 않았을까 싶다

 

풀이를 완료하고, 다른 사람의 풀이를 봤는 데 다음과 같이 Builder Pattern을 사용하여 가독성 있고 간단하게 풀이한 분이 계셔서 출처를 남기고 가져왔다

class Solution {
    public String solution(String new_id) {

        String s = new KAKAOID(new_id)
                .replaceToLowerCase()
                .filter()
                .toSingleDot()
                .noStartEndDot()
                .noBlank()
                .noGreaterThan16()
                .noLessThan2()
                .getResult();


        return s;
    }

    private static class KAKAOID {
        private String s;

        KAKAOID(String s) {
            this.s = s;
        }

        private KAKAOID replaceToLowerCase() {
            s = s.toLowerCase();
            return this;
        }

        private KAKAOID filter() {
            s = s.replaceAll("[^a-z0-9._-]", "");
            return this;
        }

        private KAKAOID toSingleDot() {
            s = s.replaceAll("[.]{2,}", ".");
            return this;
        }

        private KAKAOID noStartEndDot() {
            s = s.replaceAll("^[.]|[.]$", "");
            return this;
        }

        private KAKAOID noBlank() {
            s = s.isEmpty() ? "a" : s;
            return this;
        }

        private KAKAOID noGreaterThan16() {
            if (s.length() >= 16) {
                s = s.substring(0, 15);
            }
            s = s.replaceAll("[.]$", "");
            return this;
        }

        private KAKAOID noLessThan2() {
            StringBuilder sBuilder = new StringBuilder(s);
            while (sBuilder.length() <= 2) {
                sBuilder.append(sBuilder.charAt(sBuilder.length() - 1));
            }
            s = sBuilder.toString();
            return this;
        }

        private String getResult() {
            return s;
        }
    }
}

 

고찰


Regular Expression에 대하여 공부해 보기

 

Reading 17: Regular Expressions & Grammars

Look at the markdown and html grammars above, and compare their italic productions. Notice that not only do they differ in delimiters (_ in one case, < > tags in the other), but also in the nonterminal that is matched between those delimiters. One grammar

web.mit.edu

 

Reference


 

Lesson: Regular Expressions (The Java™ Tutorials > Essential Java Classes)

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

 

Pattern (Java Platform SE 8 )

Enables canonical equivalence. When this flag is specified then two characters will be considered to match if, and only if, their full canonical decompositions match. The expression "a\u030A", for example, will match the string "\u00E5" when this flag is s

docs.oracle.com

 

💠 빌더(Builder) 패턴 - 완벽 마스터하기

Builder Pattern 빌더 패턴(Builder Pattern)은 복잡한 객체의 생성 과정과 표현 방법을 분리하여 다양한 구성의 인스턴스를 만드는 생성 패턴이다. 생성자에 들어갈 매개 변수를 메서드로 하나하나 받아

inpa.tistory.com

 

☕ 자바 정규식(Regular Expression) 사용법 💯 정리

정규표현식 이란 정규표현식(Regular Expression)이란 문자열 데이터 중에서 원하는 조건(패턴)과 일치하는 문자열 부분을 찾아내기 위해 사용하는 것으로, 미리 정의된 기호와 문자를 이용해서 작성

inpa.tistory.com

 

 

Source Code on GitHub


GitHub에서 소스코드 보기

 

 

댓글