Algorithm - level1 신규 아이디 추천

ryan·2022년 5월 13일
1

1단계 newid의 모든 대문자를 대응되는 소문자로 치환합니다.
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이 될 때까지 반복해서 끝에 붙입니다.

내 풀이(19/100)

function solution(new_id) {
  let id = new_id.toLowerCase();
  id = id.split('').filter((e) => typeof e === 'number' || ('a' <= e && e <= 'z') || e === '-' || e === '_' || e === '.');
  for (let i = 0; i < id.length - 1; i++) {
    if (id[i] === '.' && id[i + 1] === '.') {
      id.splice(i + 1, 1);
      i -= 1;
    }
  }
  if (id[0] === '.') {
    id.splice(0, 1);
  } else if (id[id.length - 1] === '.') {
    id.splice(id.length - 1, 1);
  }

  if (!new_id) {
    new_id = 'a';
  }

  if (id.length >= 16) {
    id.splice(15, id.length - 15);
  }
  if (id[id.length - 1] === '.') {
    id.splice(id.length - 1, 1);
  }
  id = id.join('');
  if (id.length <= 2) {
    while (id.length === 3) {
      id += id[length - 1];
    }
  }
  return id;
}

다른 사람 풀이

function solution(new_id) {
  let answer = new_id
    .toLowerCase() //step 1
    .replace(/[^0-9a-z._-]/g, "") // step 2
    .replace(/\.+/g, ".") //step 3
    .replace(/^\.|\.$/g, "") //step 4
    .replace(/^$/, "a") //step 5
    .slice(0, 15)
    .replace(/\.$/, ""); //step 6
  // step7
  if (answer.length === 1) answer = answer[0].repeat(3);
  if (answer.length === 2) answer = answer + answer[1];

  return answer;
}
  • 문제를 처음 봤을 때부터 이건 정규표현식으로 풀어야된다고 생각했지만 하루종일 정규표현식만 들여다보면서 하나하나 써보기엔 학습과 프로젝트 일정이 너무 밀려서 조건,반복문으로 풀었지만, 푼 것 마저 정확도 검사에서 털리고 말았다.
  • 위 식의 repeat과 같은 기본적인 함수도 쉽게 떠오르지 않는 걸 보면 역시 기본기가 탄탄해야 응용도 할 수 있는 것 같다.
  • 내일은 알고리즘 문제 푸는 것보다 위 정규표현식을 뜯어보고 직접 써보는 걸 연습해야겠다.

---추가---

정규표현식 뜯어보기

  let answer = new_id
    .toLowerCase() //step 1
    .replace(/[^0-9a-z._-]/g, "") // step 2
 	 / / : 정규 표현식 리터럴 바뀔 일이 없는 패턴을 슬래시로 감싸서 작성
	 [^ ]: 부정 문자 클래스. 대괄호 안에 포함되지 않은 모든 문자들로 매치
	 0-9a-z._- : 부정 문자 클래스의 조건 
	 g : 전체 검색, 문자열 전체를 대상을 패턴 검색
  	 해석 : 0-9a-z._-에 해당하지 않는 문자를 찾아서 ""로 대체해라
  
  
    .replace(/\.+/g, ".") //step 3
	/ / : 위와 동일. 정규 표현식 리터럴
	\ : 이스케이핑. 다음 문자가 정규 표현식이 아닌 문자 자체로 인식하게 함.
	+ : 바로 앞에 있는 심볼이 한 번 이상 반복된 문자들과 매치
    해석 : '.'이 한 번 이상 반복된다면 '.'으로 대체해라.
    
    .replace(/^\.|\.$/g, "") //step 4
	^(대괄호 없음) : 문자 시작과 매치
    \ : 이스케이프 다음 문자 문자열로 인식
    | : 대안 부호, 앞의 정규식이거나 뒤의 정규식이거나
    $ : 앞에 있는 문자를 입력의 끝과 매치
    해석 : 문자의 시작이 '.'이거나 문자의 종료가 '.'이면 ""로 대체해라
    
    .replace(/^$/, "a") //step 5
	해석 : 문자의 시작이 끝이고, 문자의 끝이 시작(문자열이 비어있으면) "a"로 대체해라
    .slice(0, 15)
    .replace(/\.$/, ""); //step 6
	해석 : 문자의 끝이 '.'이라면 ""로 대체

정규표현식으로 다시 풀어보기(100/100)

function solution(new_id) {
  let id = new_id
    .toLowerCase()
    .replace(/[^0-9a-z-_.]/g, '')
    .replace(/\.+/g, '.')
    .replace(/^\.|\.$/g, '')
    .replace(/^$/, 'a')
    .slice(0, 15)
    .replace(/\.$/, '');

  if (id.length <= 2) {
    while (id.length < 3) {
      id += id[id.length - 1];
    }
  }
  return id;
}

정규표현식은 처음 접했던 이미지가 있어서 지레 겁먹고 외계어 같다고만 생각했는데, 이렇게 하나씩 뜯어보니까 멀게 느껴지지 않고, 유효성 검사에 상당히 유효한 도구라는 걸 체감했다. 앞으로의 코딩에서 간단한 정규표현식은 직접 작성할 수 있을 것 같다. 굳굳

profile
프론트엔드 개발자

0개의 댓글