[알고리즘 초보 여행기]정규식..? 그게 뭔데?

Eamon·2021년 2월 12일
0

algorithm

목록 보기
2/7
post-thumbnail

[프로그래머스] 2021 KAKAO BLIND RECRUITMENT > 신규 아이디 추천

문제 설명

카카오에 입사한 신입 개발자 네오는 카카오계정개발팀에 배치되어, 카카오 서비스에 가입하는 유저들의 아이디를 생성하는 업무를 담당하게 되었습니다. 네오에게 주어진 첫 업무는 새로 가입하는 유저들이 카카오 아이디 규칙에 맞지 않는 아이디를 입력했을 때, 입력된 아이디와 유사하면서 규칙에 맞는 아이디를 추천해주는 프로그램을 개발하는 것입니다.
다음은 카카오 아이디의 규칙입니다.

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

네오는 다음과 같이 7단계의 순차적인 처리 과정을 통해 신규 유저가 입력한 아이디가 카카오 아이디 규칙에 맞는 지 검사하고 규칙에 맞지 않은 경우 규칙에 맞는 새로운 아이디를 추천해 주려고 합니다.
신규 유저가 입력한 아이디가 new_id 라고 한다면,

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의 마지막 문자를 n

이 문제를 보자마자 얼마전 'http request' 와 'response' 를 배을 때 쓰려고 했지만 좌절 했던 "정규표현식(regular expression)" 을 연습해볼 기회다! 라는 생각이 먼저 들었다.

그렇게 삽질의 길로 들어서는데...

정규표현식의 역사를 살펴보면 우리의 거대한 조상 유닉스 시절부터 돌아가야하는데... 뭐 이건 나중에 알아보도록 하고, 문제로 먼저 들어가면서 정규표현식을 같이 익혀보도록하자.

문제 해석

input => new_id (str)

  • 1 이상 1,000 이하인 문자열입니다.

  • 알파벳 대문자, 알파벳 소문자, 숫자, 특수문자로 구성되어 있습니다.

  • newid에 나타날 수 있는 특수문자는 `-.~!@#$%^&*()=+[{]}:?,<>/` 로 한정됩니다.

output => answer(str)

new_id 의 문자열을 알맞게 가공해서 answer 로 내보내는 문제이다.

문제 풀이

1단계. new_id의 모든 대문자를 대응되는 소문자로 치환합니다.

const firststep = new_id.toLowerCase()

string.toLowerCase() 는 문자열을 모두 소문자로 만들어 주는 함수이며,

string.toUpperCase() 는 문자열을 모두 대문자로 만들어 주는 함수이다.

2단계, newid에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(), 마침표(.)를 제외한 모든 문자를 제거합니다.

 const secondstep = idlower.replace(/[^0-9a-z._-\s]/gi, "");

이 단계에서 처음으로 정규식이 나오는데,

정규식을 쓰는 방법부터 알아보자.

정규식 표현법은 아래와 같다.

/Patten/Flag

Patten? Flag?

헷갈리니까 바로 아래에서 예시를 들어보면,

나는 문자열에 있는 모든 A 를 탐색하고 싶다. 라고 했을때,

/A/g

이렇게 하면 되는 것이다. A는 Patten 인 것이고 g 는 전역 검색이라는 Flag 인 것이다. (select All 과 같다.)

가장 많이 쓰는 Flag는 gi 인데, 이것은 전역검색에다가 대소문자 구분없이 검색하는 Flag 이다.

자 그러면 어떻게 쓰는지 알아봤으니 2단계에서 어떤 걸 썻는지 알아보자. 아차차 그전에 Javascript 에서 정규식이 특히 많이 쓰이는 함수들을 소개해보려 한다.

string.replace(RegExp,"") : string 안에서 정규식에 맞는 문자열과 자리 바꿈

string.match(RegExp) : string 안에서 정규식에 맞는 문자열 리턴

RegExp.exec(string) : string 안에서 정규식에 맞는 문자열 리턴

나는 replace 함수를 써서 조건에 맞지않는 문자들을 제거하려했다.

정규식 안에 patten 을 살펴보면

[^0-9a-z._-\s]

[] 안에 있는 아이들이 반복되는 엇을 찾는 패턴이다.

0-9 까지의 숫자와 a-z 까지의 영어 그리고 . _ - 특수 문자들 까지 포함하며 \s 는 모든 공백을 뜻한다.

[] 안에 있는 ^ 기호는 ~ 이외에 라는 뜻이다. 즉, 내가 썻던 [^0-9a-z._-\s] 의 패턴은 숫자와 영어 그리고 특정 특수문자들과 공백 이외에 모든 문자들을 선택하는 것을 의미한다.

이렇게 선택된 문자열들을 replace 로 "" 와 바꿔주면 없어지는 효과를 볼 수 있다.

3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.

   const three = second.replace(/[.]+/gi,".");

이번에 사용한 패턴은 + 이다.

+ 기호는 정규식에서 앞의 표현식이 1회 이상 연속으로 반복되는 부분과 대응됩니다. {1,} 와 같은 의미입니다.

그러므로 /[.]+/gi 와 같은 패턴은 문자열안의 . 이 1회 이상 연속으로 반복되는 부분과 대응 됩니다.

대응되는 문자열들을 역시 replace 로 "." 문자열로 바꿔주면 마침표 하나로 치환 됩니다.

4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.

   const stepfore = (temp) => {
        if(temp === "."){
            return " "
        }
        return temp.replace(/^[.]/gi,"").replace(/[.]$/gi,"");
    }

^ 기호가 [] 안이 아니라 바깥에서 단독으로 쓰인다면 [] 입력의 시작 부분에 대응됩니다. 만약 다중행 플래그가 참으로 설정되어 있다면, 줄 바꿈 문자 바로 다음 부분과도 대응됩니다.

$ 기호는 입력의 끝 부분과 대응됩니다.

함수로 만들어 if 문을 추가해준 이유는 "." 하나가 입력되었을때 5단계를 위해서 공백으로 처리해주어야하기 때문에 만들어 주었다.

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

 const five = fore.replace(/^\s/gi,"a");

앞에서 설명했던 기호들로 앞 문자에 공백이 있을때를 캐치하고 그때 "a"로 바꿔준다.

6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다.

    const six = (Five) => {
    if(Five.length >= 16) {
        let temp = Five.substr(0,15);
        return temp.replace(/[.]$/gi,"");
    }
    return Five;
}

문자열이 16자 이상이면 substr 함수를 이용해서 15 문자들만 남기고 모두 지웁니다.

마무리

이 문제를 접하기 전에도 종종 정규식을 접할 기회가 있었습니다. 예를 들면 http tcp/ip 를 배울 때, url 에서 도메인이름을 추출해 내고싶을때 slice 함수가 아닌 정규식을 이용한 추출 방법또 있고 HTTP 문법을 배울때 header의 정보들을 추출해 낼때도 정규식을 이용하는게 유용한 적이 많았습니다. 이처럼 정규식은 문자열을 좀더 쉽게 다룰 수 있게 해줍니다. 그러나 표현 방법 차체가 어려워서 진입장벽이 어려우나, 이 예제를 풀어보면서 정규식에 대한 이해도를 높혀가는 것도 좋은 방법인 것 같습니다.

참고

[MDN 정규표현식 사이트](

profile
Steadily , Daily, Academically, Socially semi-nerd Front Engineer.

0개의 댓글