[프로그래머스] 2021 카카오 신규 아이디 추천 풀이 (JavaScript)
2025-06-12 14:56
![[프로그래머스] 2021 카카오 신규 아이디 추천 풀이 (JavaScript)](/images/posts/post3/main.png)
문제 소개
카카오 2021 BLIND RECRUITMENT에서 출제한 신규 아이디 추천 문제이다. 난이도는 level1. 사실 이 문제를 예전에 Java 로 풀어본 적이 있는데, 요즘 자바스크립트를 공부하면서 다시 풀어보고 싶었다.
➡️ 프로그래머스 문제링크
유저가 입력한 신규 아이디를 규칙에 맞는지 검사하고, 맞지 않으면 규칙에 맞는 새로운 아이디를 추천해주는 문제이다. 규칙은 다음과 같다.
- new_id의 모든 대문자를 대응되는 소문자로 치환합니다.
- newid에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(), 마침표(.)를 제외한 모든 문자를 제거합니다.
- new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.
- new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.
- new_id가 빈 문자열이라면, new_id에 “a”를 대입합니다.
- new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.
만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.- new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.
규칙은 7단계로 문자열을 계속 맞게 필터링해주는 단순 구현 문제이다.
내가 푼 방식
일단 엄청 조건이 많다.ㄷㄷ 까다로운 것 같지만, 단계 별로 하나씩 바꿔서 출력해서 차근 차근 접근하면 된다. 문자열에 대한 자바스크립트 내장 함수를 잘 이용해야겠다고 생각했고 로그를 찍어보면서 디버깅했다.
생각보다 문자열을 자르는 거라 던지, 2번 이상 연속된 부분을 구하는 부분 등에서 헷갈린 부분이 많았다. 예를 들면 문자열을 자를 때 subString() 을 사용하자! 라고 생각은 했는데 인덱스에서 어디까지 잘리는지 자세한 사용법은 모르고 있었다..(역시 이래서 해봐야한다;;)
연속된 부분을 구할때도 바로 떠오르는 함수가 없었기에 단순 구현해봤다.
아래는 내가 푼 코드다.
function solution(new_id) {
let answer = String(new_id);
// 1단계 : 대문자 -> 소문자
answer = answer.toLowerCase();
// 2단계 : 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거
let secondAnswer = '';
for (let char of answer) {
if (
(char >= 'a' && char <= 'z') || // 소문자이면
!isNaN(Number(char)) ||
char === '-' ||
char === '_' ||
char === '.'
) {
secondAnswer += char;
}
}
// 3단계 : 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환
let thirdAnswer = '';
let before = '';
for (let char of secondAnswer) {
// . 연속이면 . 으로 바꾸기
if (before === '.' && char === '.') {
// 제일 마지막 글자가 . 이면 넣지 않기
if (!thirdAnswer.endsWith('.')) {
thirdAnswer += '.';
}
} else {
thirdAnswer += char;
before = char;
}
}
// 4단계 : 마침표(.)가 처음이나 끝에 위치한다면 제거
let fourthAnswser = thirdAnswer;
if (thirdAnswer.startsWith('.')) {
fourthAnswser = fourthAnswser.slice(1);
}
if (fourthAnswser.endsWith('.')) {
fourthAnswser = fourthAnswser.substring(0, fourthAnswser.length - 1);
}
// 5단계 : 빈 문자열이라면, new_id에 "a"를 대입
let fitthAnswer = fourthAnswser;
if (fitthAnswer === '') {
fitthAnswer += 'a';
}
// 6단계 :
// 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거
// 만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거
let sixthAnwer = fitthAnswer;
if (sixthAnwer.length >= 16) {
sixthAnwer = sixthAnwer.substring(0, 15);
if (sixthAnwer.endsWith('.')) {
sixthAnwer = sixthAnwer.substring(0, sixthAnwer.length - 1);
}
}
// 7단계 : 길이가 2자 이하라면,
// new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙임
let seventhAnwer = sixthAnwer;
if (seventhAnwer.length <= 2) {
let lastChar = seventhAnwer.substring(seventhAnwer.length - 1);
while (seventhAnwer.length < 3) {
seventhAnwer += lastChar;
}
}
return answer;
}
그냥 보기만 해도 길다😧 참고만 하고 따라 하신 마시길..결국엔 테스트 케이스를 다 통과하긴 했는데, 어딘가 맘에 안든다. 일단 변수부터 단계마다 모두 선언했고 불필요한 코드들이 많았음.. (메모리 관리 안할꺼냐..)
그래서 풀이 방식의 장단점을 정리해보았다.
장점
- 단계별로 어떻게 동작하는 지가 보여서 가시적임
- 디버깅 하기 쉬움
단점
- 변수 선언이 너무 많음
- 코드 길이가 길다
- 메모리 사용량 증가
코드가 너무 길었기 때문에 좀 더 간략하게 줄이고 싶은 마음이 컸다.
다른 사람이 푼 방식
function solution(new_id) {
let answer = new_id
.toLowerCase() // 1
.replace(/[^a-z0-9_.-]/g, '') // 2
.replace(/\.{2,}/g, '.') // 3
.replace(/^\.|\.$/g, '') // 4
.replace(/^$/, 'a') // 5
.substring(0, 15)
.replace(/\.$/, ''); // 6
//7
return answer.padEnd(3, answer[answer.length - 1]);
}
정규식을 사용해서 코드의 복잡성을 줄이고, 메서드 체이닝을 이용해서 쓸 데없는 변수 선언을 줄였다. 정규식으로 풀 수 있다는 걸 왜 생각을 못했을까..?? 정규식이 나는 코드적으로 확 안 와닿아서 생각이 안났는데, 모르는 사람이 보면 가독성은 안좋지만 오히려 코드가 짧아지니까 주석만 잘 쓰면 쓰는 게 좋다고 생각한다.
여기서 정규식 사용법 알아가기
.replace(/[^a-z0-9_.-]/g, "")
- [^…] → 괄호 안에 있는 문자를 제외한 것 (!==)
- a-z → 알파벳 소문자
- 0-9 → 숫자
- _.- → 밑줄, 점, 하이픈
- / /g → global 플래그 (전체 검색) 즉, 소문자, 숫자, _, ., - 이외 문자를 모두 ""(공백) 으로 제거한다.
.replace(/\.{2,}/g, ".")
- . → 마침표
- {2,} → 2개 이상
- g → 전체
.(점)이 2개 이상 연속 된 것을 하나의 .(점) 으로 줄인다.
.replace(/^$/, "a")
- ^$ → 시작과 끝이 바로 맞닿은 경우 = 문자열이 비어 있음 ^$이 빈 문자열이라는 뜻인데 비어 있으면 a 로 대체한다.
그리고 마지막에 나온 padEnd()
함수는 처음 보는 녀석이어서 잘 몰랐는데, 원하는 문자열 길이만큼 끝에 문자를 덧붙여주는 함수였다.
str.padEnd(최종 문자열의 길이, 끝에 채울 문자열)
answer.padEnd(3, answer[answer.length - 1]);
문자열이 3보다 짧다면 아무일이 없겠지만, 짧으면 길이를 3만큼 늘리고, 비어있는 나머지 공간에 answer의 끝문자를 다 채워준다. 이런 함수가 없었다면 while 반복문으로 3이 될때까지 문자열을 추가해주는 로직을 반복했을 거다. 고정적인 길이를 유지하고 싶을 때 사용하면 유용하게 쓰일 것 같다.
결론
- 자바스크립트 문자열 체이닝 사용하기
- 정규식 규칙 알기 및 제대로 활용하기
- 문자열을 길이만큼 특정 문자로 채워줄때
padEnd()
를 사용할 것