[Java, Programmers] 신규 아이디 추천

🥺 주절주절

국비 과정이 끝나고 남은 최종 프로젝트와 이력서를 들고 시장판 호객 알바생처럼 이력서를 돌리고 있다.
그리고 돌릴 수록 급속도로 깎여나가는 나의 자존감과 멘탈 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
대체 이따구 실력으로 어떻게 취업하려고 했지요?! 나같아도 안뽑겠다!!!!! 엉엉 ㅠㅠㅠ 니 죄를 니가 알렸다..!

하나. 프로젝트를 처음부터 스프링으로 강행하지 않은 죄.
하나. 매일 알고리즘 문제 하나씩 풀어보지 않은 죄.
하나. 자바 8 공부를 매일 조금씩 하지 않은 죄.
마지막.... 감히 개발자를 꿈꾼 죄...!

하지만 나는 능이버섯.. 죽지 않는 각설이.. 욕심나는 건 어떻게든 해결해야 만족하는 똥고집쟁이..
그런고로 이미 늦은거 매일 대출 이자라도 갚는단 기분으로 공부하고 있다.

알고리즘 푼건 기록으로 남겨두고 훗날의 내 자존감 치료제로 쓰기!
프로젝트가 막힐 때 다시 열어보고 셀프 회복제가 되어주었던 구구단처럼.


⛑ Programmers Lv.1 신규 아이디 추천

📍문제 조건

✔️ 아이디 규칙

  • 아이디의 길이는 3자 이상 15자 이하여야 합니다.
  • 아이디알파벳 소문자, 숫자, -, _, . 문자만 사용할 수 있습니다.
  • 단, .처음에 사용할 수 없으며 또한 연속으로 사용할 수 없습니다.

✔️ 단계별 처리 로직

  • 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의 모든 대문자를 대응되는 소문자로 치환합니다.

// 1단계 : 소문자로 만들고 char stream 으로 만들기
        IntStream id = new_id.toLowerCase().chars();

요즘 java 8 in action 을 깨작 깨작 공부하고 있는데, 책으로만 보는것 보다 자꾸 써버릇 해야 할 것 같아서 의식적으로 stream으로 먼저 시도해보고 있다. 그래서 String new_id -> toLowerCase() -> chars() String -> String -> IntStream 으로 변환해주었다.
굳이 stream 으로 변환 해 준 이유는, 2단계에서 조건에 맞춰 문자를 거를 때 for문 말고 stream 으로 filter() 해주고 싶었기때문!

하지만.. 어차피 아래에서 정규식으로 거를꺼, 처음부터 stream 이 아니라 정규식으로 다 거르는게 더 깔끔하고 억지스럽지 않았을 것 같다. 실제로 다른 분 풀이를 보니까 그게 더 효율적이어 보였고.

아무튼 1단계는 이렇게 해서 해결!

✔️ 2단계 : new_id에서 알파벳 소문자, 숫자, -_.를 제외한 모든 문자를 제거합니다.

// 2단계 : 조건에 안맞는 문자 제거
        // 조건 : 소문자, 숫자, -, _, . 만 가능
        StringBuffer sb = new StringBuffer(); // 걸러낸 애들 저장할 버퍼
        id.filter( c -> ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '-' || c == '_' || c == '.')
                .mapToObj( c -> (char)c)
                .forEach( c-> sb.append(c));

위에서 만든 streamIntStream 이므로 char 값과 비교가 가능하다. filter() 로 각 조건에 맞는 char 만 남긴 뒤, mapToObj()streamchar 타입으로 변환! 최종적으로 forEach 안에서 StringBuffer 에 담아준다.
forEach 가 돌 때 최대한 쓰레기가 생기지 않도록 버퍼를 생성해줬다.

하지만 아래에서 replaceAll 사용 외에 다른 법을 고안해내지 못했기때문에... ㅋ .. 커다란 효과는 없을 것 같다 ㅎ...

✔️ 3단계 : new_id에서 .가 2번 이상 연속된 부분을 하나의 .로 치환합니다.

// 3단계 : . 가 연속이면 1개만 남기기
        String step3 = sb.toString().replaceAll("\\.{2,}",".");

이실직고! 정규식 외에 다른 방법이 전혀 떠오르지 않았다. 다 풀고나서 다른 분들 풀이를 보니 indexOf("..") >= 0 이라거나.. 맨 처음 1단계에서 문자를 거를 때 .. 값을 거르고 들어오거나.. 등등의 방법들로 정규식 없이 푸셨던데, 솔직히 '알고리즘' 에는 저런 방법이 더 가깝지 않나 싶어서 반성!

정규식은 정규식 문법을 알아먹지 못하면 '왜' 를 유추하기 힘들지만, 그 외의 방법은 "아 이렇게 걸러졌구나~" 하는 걸 코드로 이해할 수 있어서 개인적으로 더 대단해보였다.

✔️ 4단계 : new_id에서 .가 처음이나 끝에 위치한다면 제거합니다.

// 4단계 : . 가 처음이나 끝이면 제거
        String step4 = step3.replaceAll("^\\.|\\.$","");

이실직고 222 정규식 왜 다른 방법 머리 텅텅 222
다른 분들은 startWith(), endWith(), charAt(0) 등으로 푸신 걸 보고 끄덕끄덕 한번 더 공부.
어차피 replaceAll() 로 거를 거라서 최종 코드에는 3단계와 4단계를 묶어줬다.

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

// 5단계 : 공백이면 a 로 변환
        if ( answer.equals("")){
            answer = "a";
        }

isBlank() , length() == 0 등의 방법도 있더라. 내 머리는 equals() 너만 보여 짝사랑인 점을 반성...
뭔가 다양한 방법 만큼 효율 문제도 다르지 않을까 궁금한데 나중에 따로 찾아봐야겠다. (언젠간)

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

// 6단계 : 15자리 이상은 제거, 제거 후 . 가 끝이면 제거
        if ( answer.length() > 15){
            answer = answer.substring(0,15).replaceAll("^\\.|\\.$","");
        }

chatAt(14) 와 삼항연산자로 해결하신 분도 있었는데 나는 또 정규식 밖에 모르는 바보~ ㅎ.ㅎ

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

// 7단계 : 3자리 이하면 마지막 문자를 3자리까지 반복
        while ( answer.length() < 3){
            answer += answer.charAt(answer.length()-1);
        }

이 부분은 다들 비슷하게 for문 으로 해결하신 것 같다. 여기서 IntStream 으로 변환 후 내 1단계와 비슷한 로직으로 해결하신 분도 있었는데, 내가 아직 공부 못한 range, joining 등이 있어서 신기!


전체 풀이 코드

public class AlgorismEx02 {
    public static String solution(String new_id) {

        String answer = "";

        // 1단계 : 소문자로 만들고 char stream 으로 만들기
        IntStream id = new_id.toLowerCase().chars();

        // 2단계 : 조건에 안맞는 문자 제거
        // 조건 : 소문자, 숫자, -, _, . 만 가능
        StringBuffer sb = new StringBuffer(); // 걸러낸 애들 저장할 버퍼
        id.filter(c -> ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '-' || c == '_' || c == '.')
                .mapToObj(c -> (char) c)
                .forEach(c -> sb.append(c));
        //answer = sb.toString();

        // 3단계 : . 가 연속이면 1개만 남기기
        // 4단계 : . 가 처음이나 끝이면 제거
        String step3 = sb.toString().replaceAll("\\.{2,}", ".").replaceAll("^\\.|\\.$", "");
        answer = step3;

        // 5단계 : 공백이면 a 로 변환
        if (answer.equals("")) {
            answer = "a";
        }

        // 6단계 : 15자리 이상은 제거, 제거 후 . 가 끝이면 제거
        if (answer.length() > 15) {
            answer = answer.substring(0, 15).replaceAll("^\\.|\\.$", "");
        }

        // 7단계 : 3자리 이하면 마지막 문자를 3자리까지 반복
        while (answer.length() < 3) {
            answer += answer.charAt(answer.length() - 1);
        }

        return answer;
    }

🤪 마무리 주절주절

알고리즘 풀이 능력은 결국 하루 아침에 해결될 문제가 아닌거니 조급해 하지말자.
그저 바위에 한방울씩 떨어지는 물처럼 찬찬히 깨부순다 생각하기.

좋은 웹페이지 즐겨찾기