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이 될 때까지 반복해서 끝에 붙입니다.
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
해석 : 문자의 끝이 '.'이라면 ""로 대체
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;
}
정규표현식은 처음 접했던 이미지가 있어서 지레 겁먹고 외계어 같다고만 생각했는데, 이렇게 하나씩 뜯어보니까 멀게 느껴지지 않고, 유효성 검사에 상당히 유효한 도구라는 걸 체감했다. 앞으로의 코딩에서 간단한 정규표현식은 직접 작성할 수 있을 것 같다. 굳굳