[코딩테스트] 프로그래머스 - 신규 아이디 추천(JAVA)

입력 받은 아이디를 체크하여 규칙에 맞게 추천하는 프로그램 개발 7단계의 규칙을 적용해야 하는데 그 내용은 아래와 같다.


제한사항

  • 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이 될 때까지 반복해서 끝에 붙입니다.

풀이

  • String Method, 정규식에 대한 이해가 있다면 쉽게 풀 수 있다.
  • Optional을 이용하여 풀어보았다.
public String solution(String new_id) {

    /**
     * Optional을 사용하기 위해 Optional.ofNullable로 감쌉니다.
     * 그럴일은 없겠지만 NPE를 회피하기위해서.. ofNullable를 선택합니다.
     */
    return Optional.ofNullable(new_id)

    /**
     * Optional map 메서드는 mapper 함수의 반환값을 Optional 객체로 감쌉니다.
     * 1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
     * String의 toLowerCase 메서드를 통해 문자열 소문자로 치환!
     */
    .map(String::toLowerCase)

    /**
     * 2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.
     * 이 경우 replaceAll을 사용하는게 좋습니다.
     * ^의 경우 문자열의 시작이지만 []안에 들어간 ^s는 Not의 의미를 갖습니다.
     * a-z는 소문자, \d는 숫자, -_.s는 특수 문자
     * *는 없거나 또는 1개 이상
     */
    .map(str -> str.replaceAll("[^a-z\\d\\-_.]*", ""))

    /**
     * 3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
     * 2단계와 마찬가지로 replaceAll 사용
     * (.)는 마침표, {2,}는 2회 이상
     */
    .map(str -> str.replaceAll("\\.{2,}", "."))

    /**
     * 4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
     * 2단계와 마찬가지로 replaceAll 사용
     * 2단계와 다르게 ^가 [.] 바깥에 위치하니 문자열의 시작
     * |는 or의 의미, [.]$는 문자열의 끝이 (.)로 끝납니다.
     */
    .map(str -> str.replaceAll("^[.]|[.]$", ""))

    /**
     * 5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.
     * String의 isBlank()를 이용하면 단숨에 해결, 빈 값 여부를 체크합니다.
     */
    .map(str -> str.isBlank() ? "a" : str)

    /**
     * 6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
     * 만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.
     * simple if문을 넣어 16자 이상이면 substring, 그외에는 그대로 return
     */
    .map(str -> str.length() >= 16 ? str.substring(0, 15) : str)

    /**
     * 그리고 마침표 [.]$로 끝나면 변환
     */
    .map(str -> str.replaceAll("[.]$", ""))

    /**
     * 7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.
     * 6단계와 마찬가지로 simple if문 추가
     * 마지막 문자를 파싱 후 반복해서 3자리를 만들어야 합니다.
     * for문을 이용화면 너무 코드가 지저분해지고.. 이럴떄 repeat 메서드를 이용하면 편합니다.
     * str.repeat(N)는 str을 N번 반복하여 concat한 값을 return 합니다.
     */
    .map(str -> str.length() <= 2 ? str + str.substring(str.length() - 1)
    .repeat(3 - str.length()) : str)

    /**
     * optinal은 get()으로 끝 마무리 지으면 뭔가 찝찝합니다.. 인텔리제이를 사용하고 있으면 경고 문구가 노출되네요..
     * 기본적으로 Optional.orElseThrow로 값이 없을 경우 에러를 생성하는 형태를 선호하나 코딩테스트에 맞게 깔끔하게 할려면 Stream으로 변환합니다.
     */
    .stream()
    .collect(Collectors.joining());
}

주석을 뺀 코드도 따로 공개합니다~!

public String solution(String new_id) {

    return Optional.ofNullable(new_id)
    .map(String::toLowerCase)
    .map(str -> str.replaceAll("[^a-z\\d\\-_.]*", ""))
    .map(str -> str.replaceAll("\\.{2,}", "."))
    .map(str -> str.replaceAll("^[.]|[.]$", ""))
    .map(str -> str.isBlank() ? "a" : str)
    .map(str -> str.length() >= 16 ? str.substring(0, 15) : str)
    .map(str -> str.replaceAll("[.]$", ""))
    .map(str -> str.length() <= 2 ? str + str.substring(str.length() - 1)
    .repeat(3 - str.length()) : str)
    .stream()
    .collect(Collectors.joining());
}
코딩테스트 프로그래머스

2023

[linux] shell script version compare

최대 1 분 소요

개요 linux를 사용하다 보면 version 비교하는 기능이 필요합니다. 특히 기존 설치된 패키지의 version을 확인하여 업데이트할 경우가 있겠죠. 아래와 같이 간단한 shell script로 구현할 수 있습니다.

[jenkins] jenkins docker install

2 분 소요

ci/cd 오픈소스 도구로 가장 많이 사랑 받는 jenkins에 대해 포스팅 해보겠습니다. 먼저 설치부터 해야겠지요? 항상 패키지 매니저로 설치했었는데 이번에는 docker로 설치해보도록 하겠습니다.

[springboot] springboot history

2 분 소요

springboot 탄생 배경 springboot란 spring framework를 좀 더 쉽게 개발/배포할려는 목적으로 만들어 졌습니다. 2012년 Mike Youngstrom은 spring 프레임워크에서 컨테이너 없는 웹 애플리케이션 아키텍처에 대한 지원을 요청하는 spring...

[springboot] springboot3 querydsl 적용

1 분 소요

개요 springboot3로 메이저 업그레이드 되면서 JPA + querydsl 셋팅 환경에 변화가 생겼습니다. 기존 의존성으로는 작동하지 않고 jakarta classification을 추가해야 작동하는 이슈가 발생합니다. springboot3부터 javax -> jakar...

[springboot] springboot3 migration

최대 1 분 소요

개요 2022년 하반기에 springboot3가 공식 release 되었습니다. springboot2가 2018년 상반기에 release되고 나서 새롭게 판올림 버전으로 가장 큰 변화로는 아래와 같습니다. spring framework 6 적용 최소 사양 JDK 17 ...

[springboot] springboot initializer

1 분 소요

개요 항상 intellij ultimate 버전만 사용하고 있었는데 무슨 바람이 난건지.. intellij ce 버전에 도전하였습니다. springboot 프로젝트 생성이며.. 그 밖에 기본적으로 될꺼라 싶은것 중에 안되는 녀석들도 꽤 있더군요. 이번 시간엔 간단하게 spingbo...

[querydsl] querydsl No release for a long time

최대 1 분 소요

개요 JPA를 spring data jpa + querydsl과의 조합으로 접하는 경우가 많습니다. spring data jpa에서 제공해주는 specification으로도 충분히 해낼수 있지만 querydsl에 비할바는 아닙니다. entity에 wrapper Q클래스를 생성하여 ...

[jekyll] jekyll install

6 분 소요

개요 오랫동안 방치했던 블로그를 다시 열면서 jekyll를 다시 설치해봤습니다. 설치 jekyll 프로젝트로 이동하여 아래 명령어를 입력합니다. gem install jekyll bundler Fetching pathutil-0.16.2.gem Fetching terminal-t...

맨 위로 이동 ↑

2021

[linux] Parse yaml

1 분 소요

bash를 사용하여 yaml 파일을 파싱 및 환경 변수로 손쉽게 등록할 수 있습니다.

[유틸리티] Mock Http Status Test

최대 1 분 소요

외부 통신에 대한 Error 처리는 앱을 더욱 더 견고하게 만들 수 있습니다. Error 처리를 위해 엔드포인트에 대한 Http Status Code를 억지로 생성하는것은 매우 귀찮은 일이라고 할까요? 보다 간편하게 Mock 서버를 두는게 더 효율적이라고 볼 수 있습니다.

맨 위로 이동 ↑