[JavaScript] 정규식 작성 방법

Joosi_Cool·2023년 1월 26일
2

Frond-End

목록 보기
5/8
post-thumbnail

이번 블로깅에선 정규식이란 무엇이며, 어떻게 활용하는지 알아보려한다.
코딩테스트를 준비하다보면, 자주 언급되며 쓰이는것이 정규식이다. 하지만 정규식을 처음 보면 도대체 뭘 의미하는지 이해하기에 힘들다. 이에 대해 자세히 다루어보고, JS에서도 이를 사용해보려 한다.

정규식이란?

공식문서에 대해 뭐라고 써있을까?

정규표현식, 또는 정규식은 문자열에서 특정 문자 조합을 찾기 위한 패턴입니다.

공식문서에는 위와 같이 정의되어있다. 특정 문자조합을 찾는다?? 조금 이해가 어렵다. 예시를 하나 들어보자.

My phone number is 010-xxxx-xxxx. And your phone number is 010-0000-0000.

위와 같은 문자열이 있다고 가정해보자. 이때 전화번호 값만 찾고 싶다면? 이때, 쓰는 것이 정규표현식 이다. 전화번호는 숫자-숫자-숫자 라는 패턴을 가지고 있다. 이러한 패턴을 찾아서, 정규식을 만들 수 있다. 이러한 패턴을 가진 문자열을 찾는 것이다.
쉽게 요약하면 위와 같은 문자열에서 전화번호와 같은 특정 문자 조합을 찾는 패턴을 말한다.




정규식 만드는 법

만드는 방법은 총 두가지 이다. 정규 표현식 리터럴 , RegExp 객체의 생성자 호출.
말이 너무 어렵다. 아래 좀 더 자세히 봅시다. flags에 대한 것이 나오는데, 이는 뒤에 설명하겠으니, 잠깐 넘어가자.

1. 정규표현식 리터럴

const regex = /pattern/flags;

이 방법은 슬래시(/)패턴으로 감싸는 방식이다. 슬래시 안에 앞서 말한 패턴을 넣어서 정규식을 만들어주는 방식이다.
이는 스크립트를 불러올 때 컴파일 되므로, 실행 도중에 바뀌지 않는 패턴일 때 사용하는 것이 좋습니다.

2. RegExp 객체의 생성자 호출

const regex = new RegExp('pattern',flags);

이는 RegExp 객체의 생성자를 호출하여, 정규표현식을 만드는 방식이 되겠습니다.
리터럴과 다르게, 이는 런타임에 컴파일 되기 때문에 실행 도중에 바뀔 수 있는 패턴이나, 사용자 입력에 따라서 유동적으로 바뀔 수 있을때 이를 활용하는 것이 좋다.



Pattern 만드는 법

사실 이 부분이 가장 중요하다. 문자열에서 원하는 것을 뽑고자 할때, 원하는 패턴을 만드는 것이 매우 중요하다. 이는 어떻게 만들까?
만약 abc가 들어간 문자열을 찾고 싶다면, 이를 어떻게 정규표현식을 세울 수 있을까?

const regex = /abc/flags

우리의 패턴은 abc에 대한 것이기 때문에, 이런식으로 정규식에 abc 값을 넣어주면 된다. 정말 간단하다. 하지만 좀 더 복잡하다면? 예를 들어 전화번호는 숫자 2개 이상-숫자 3개 이상 -숫자4개 이런식으로 패턴을 만들어줘야 하는데, 어떻게 만들까?
정규식 문법을 총 4가지로 나누어서 보려한다.

Groups and ranges(그룹 지거나 범위를 정해줌)

Chracter
|또는 (or)
( )그룹
[ ]문자셋
[^]부정 문자셋
[?:]찾지만 기억하지는 않음

1. | (or)

만약 red라는 문자열 또는 blue라는 문자열을 찾고 싶을때 활용할 수 있는 문법이다.

const regex = /red|blue/flags

이렇게 입력하면 red 또는 blue인 문자열을 가진 패턴을 만들 수 있다. (두가지 중 한가지만 만족한다면 매치)


2. ( ) (그룹)

이는 다른 문법들을 쓸때, 그룹으로 묶어버릴 수 있다. 말이 좀 어렵다. 예시를 보다.
예를 들어, on1과 on2를 찾고 싶다면 그룹을 이용하여 아래와 같이 패턴을 만들 수 있다.

const regex = /on(1|2)/flags

on뒤에 1이나 2가 오는 문자열을 매치시키겠다!! 라는 뜻입니다.
단, 여기서 추가적인 기능이 그룹을 할때 그룹1 = on1, 그룹2 = on2로 저장이 됩니다.
만약 이런식으로 그룹을 따로 지정해주지 않고 싶다면 어떻게 해야 할까?
이때는 [?:] 이것을 쓰면 됩니다.

const regex = /on(?:1|2)/flags

이런 식으로 하게 된다면 그룹을 따로 나누지 않고 하나로 보고 매치시킵니다.


3. [ ] (문자셋)

만약 그룹에서 1,2 둘 중에 하나가 아니라 1~10까지라면 어떨까? 1|2|3|......|9까지 전부 넣어줄까?
이때 쓰는 것이 문자셋이다. 아래와 같이 가능하다.

const regex = /on[123456789]/flags

뿐만 아니라 - 를 이용하여 어디서부터 어디까지 이를 알려줄 수 있다.

const regex = /on[1-9]/flags

이런식으로 편하게 패턴을 만들어낼 수 있다. [ ]안에 하나라도 만족한다면 매치시킨다.


4. [^] (부정 문자셋)

만약 1~9까지 빼고 매치시키고 싶다면 어떻게 할까? 이때 쓰는 것이 부정 문자셋이다.
아래 예시코드를 봐보자.

const regex = /^[1-9]/flags

이런식으로 한다면 문자열에서 1~9를 제외한 것을 매치시킨다.




Quantifiers(수량 관련)

Chracter
?없어도 되고, 있어도 될때(zero or one)
*?랑 같은데 2개 이상이어도 됌(zero or more)
+하나 또는 많이(one or more)
{ n }n번 반복
{min,max}최대 최소

1. ? (zero or one)

이는 특정 문자 뒤에 두게 되면 있는 것, 없는 것 둘다 매치 시킨다.

const regex = /ones?/flags

이렇게 두었다면 s 가 있는 것, 없는 것 둘다 매치가 된다. 그래서 one과 ones 두개가 매치 된다. 이렇다면 그 뒤에 나올 * , + 둘다 이해가 쉬울 것이다.


2. * (zero or more)

? 랑 비슷은 하지만 ? 는 없거나 한개 있거나를 매치시킨다. 위에 예시 코드를 그대로 가져와보자.

const regex = /ones*/flags

이렇게 된다면 one, ones, oness, onesssssss 이런것들이 매치된다는 말이다. ?는 one과 s가 한개인 ones만 매치가 된다.


3. + (one or more)

+ 는 없는것은 매치하지 않는다. 그 문자가 꼭 하나는 있어야 하며, 더 많아도 매치 시킨다.

const regex = /ones+/flags

위의 코드의 경우에는 one은 매치키지 않는다.


4. { n } (n번 반복)

+* 는 지정한 문자를 한개 이상 잡아주긴 하지만, 만약 뚜렷한 수치 예를 들어 3개를 잡아내고 싶을때는 어떻게 할까? 이때 쓰는것이 { n } 이다.

const regex = /ones{3}/flags

위의 정규식의 경우, onesss만을 잡게 된다.
이걸 이용하면 되게 많은 것을 할 수 있다. 만약 abc를 3번 반복하는 문자열을 찾고 싶다면 정규식을 어떻게 세울까? 우선 abc에 대한 패턴에 () 를 이용하여 {3} 을 뒤에 붙여주면 된다.

const regex = /(abc){3}/flags

5. {min,max} (최대 최소)

이것은 {n} 과 매우 유사하며, 좀 더 확장 버전이라고 생각하면 이해하기 좋다.
만약 우리가 어떤 문자열이 3~5번 반복하는 패턴이 있다고 가정하면 이를 어떻게 만들까? {3},{4},{5} 이런식으로 따로따로 매치 시켜주어야 할까? 매우 번거롭다. 이때 쓰는 것이 이 문법이다.

const regex = /ones{3,5}/flags

이렇게 정규식을 세운다면, onesss, onessss, onesssss 만을 매치시킨다.
만약에 최대를 비어놓는다면? 이렇게 된다면 그 이상을 말한다.

const regex = /ones{3,}/flags

이런 정규식은 s가 3번 이상 들어간 것을 매치시킨다. 그렇다면 최대를 비우면 어떻게 될까? 예상한 것 처럼 그 이하를 매치시킨다.




Boundary-type(기준 경계)


Chracter
\b단어 경계
\B단어 경계 제외
^단어의 시작
$단어의 끝

1. \b (단어 경계)

단어 경계? 말이 너무 어렵다 예시코드를 바로 봐보자.

const regex = /\bch/flags

이렇게 구성한다면 문자열에서 단어 기준으로 ch로 시작하는 ch만을 매치시킨다.
예를 들어서, 아래와 같은 문자열이 있다고 가정해보자.

string = cheese cheeses check is checking

이런 문자열에 위 정규식을 매치 시킨다면 어떠한 것이 매치될까? ch로 시작하는 단어는 cheese, cheeses, check, checking이 있다. 이때 ch를 매치시킨다. 따라서 ch 4개가 매치된다는 것이다.

string = cheese cheeses check is checking

\b를 뒤에두면, ch로 시작하는 것이 아니라 끝나는 것을 매치시킬 수 있다.

const regex = /s\b/flags

이러한 정규식은 뒤에 s로 끝나는 단어에서 s만을 매치시킨다.

string = cheese cheeses check is checking


2. \B (단어 경계 제외)

\B\b를 제외한 것을 매치시킨다.... 본인이 이를 치면서도 이해하기에 어렵다. 바로 예시 코드로 가보자.

const regex = /\Bch/flags

이렇게 정규식을 만들면 ch로 시작하는 단어를 찾아서 ch를 제외한 것을 매치시킨다. \b 는 ch로 시작하는 단어를 찾아서 ch만을 매치시켰지만 반대로 \B 는 ch를 제외한 것을 매치시킨다.

string = cheese cheeses check is checking

이러한 문자열이 있다고 한다면, 아래와 같이 매치시킨다.

string = cheese cheeses check is checking

\B 도 마찬가지로 뒤에 적을 수도 있다. 이렇게 되면 지정문자가 마지막에 있는 것을 찾아서, 그 외에 것을 매치시킨다.

const regex = /s\B/flags

이렇다면, 아래 예시 문자열 기준으로 결과는 아래와 같다.

string = cheese cheeses check is checking

나는 단어기준이 아니라... 문장 기준으로 보고 싶은데 이때는 어떻게 하지?? 이때 쓰는 것이 뒤에 나오는 것 들이다.


3. ( ^ ) (문장의 시작)

이것이 앞에 것과 다른점은 단어 기준이 아니라 문장 기준으로 매치시킨다.
아래와 같은 여러 문장을 담고 있는 문자열이 있다고 가정해보자.

cheese cheeses check is checking
checking cheese cheeses is check
cheese cheeses check is checking
is check cheese cheeses checking

나는 이 문자열 중에 is로 시작하는 문장을 찾고 싶다면? 아래와 같이 정규식을 만들어주면 된다.

const regex = /^is/flags;

이렇게 되면 아래와 같이 매치된다.

cheese cheeses check is checking
checking cheese cheeses is check
cheese cheeses check is checking
is check cheese cheeses checking

이것이 이해가 갔다면 뒤에 것은 설명을 듣지 않아도 이해가 갈 것이다.


4. ( $ ) (문장의 끝)

내가 만약에 checking로 끝나는 문장의 ing를 가지고 오고 싶다면?
아래와 같이 정규식으로 세우면 된다.

const regex = /$checking/flags;

그렇다면 이젠 예상이 가듯이 결과는 아래와 같이 매치된다.

cheese cheeses check is checking
checking cheese cheeses is check
cheese cheeses check is checking
is check cheese cheeses checking




Character classes(특정 문자)


Chracter
\ 특수 문자가 아닌 문자
.All (문자, 숫자, 특수 문자, 공백 모두 포함)
\d모든 숫자
\D모든 숫자 빼고 전부
\w모든 문자
\W모든 문자 빼고 전부
\s모든 공백
\s모든 공백 제외

이 문법들은 어떤 문자 집합을 포함하는 단축키? 라고 생각하면 편할 것 같다. 아래 설명을 편하게 읽어보자.


1. ( \ ) (특수 문자가 아닌 문자)

우리가 right? 라는 문자를 찾고 싶다면 어떻게 할까?

const regex = /right?/flags;

이렇게 정규식을 쓸 것이다. 이것이 맞을까? 이 정규식의 의미는 right인데 t는 없어도 되고 있어도 돼!! 이다. ? 가 문법으로 받아들여진 것이다. ?, . 등의 문자를 찾고 싶은데 이를 그대로 쓰면 문법으로 받아들여진다. 이럴때 쓰는 것이 \ 이것이다.


위를 수정하면 아래와 같다.

const regex = /right\?/flags;

2. ( . ) (All)

이 점은 모든 것을 매치시킨다. 숫자, 문자, 특수 기호 뿐만 아니라 공백까지 매치시킨다.

const regex = /./flags;

cheese cheeses** check#@ is checking1242

위에 정규식을 아래 문자열에 적용하면 전부 다 매치된다.


3. ( \d ) (모든 숫자)

이는 문자열에서 숫자에 해당하는 것을 모두 리턴한다.

const regex = /\d/flags;

cheese cheeses** check#@ is checking1242

예상한 바와 같이 1242 만 매치된다.


4. ( \D ) (모든 숫자 제외)

이는 문자열에서 숫자에 해당하는 것 제외하고 모든 것을 매치시킨다.

const regex = /\D/flags;

cheese cheeses** check#@ is checking1242

위와 같은 정규식이라면 1242를 제외한 나머지가 매치된다.


5. ( \w ) (모든 문자)

이는 문자열에서 문자에 해당하는 모든 것을 매치시킨다.

const regex = /\w/flags;

이때 주의사항은 여기서 말하는 문자는 특수문자를 제외한 영어, 한글, 숫자를 말한다.

6. ( \W ) (모든 문자 제외)

이는 문자열에서 문자에 해당하는 것을 제외한 모든 것을 매치시킨다.

const regex = /\W/flags;

이를 통해 공백, 특수문자들을 매치시킬 수 있다.


7. ( \s ) (모든 공백)

이는 문자열에서 모든 공백을 매칭시킨다.

const regex = /\s/flags;

8. ( \S ) (모든 공백 제외)

이는 문자열에서 모든 공백을 제외한 모든 것을 매칭시킨다.

const regex = /\s/flags;

flag란?

flag란, 정규식에서 패턴 뒤에 들어가는 것으로 검색 모드로 생각해주면 편하다.
문자열에서 패턴을 찾는데 있어서, 모든 줄을 다 볼 수도 있고 한개만 매치할수도 있고, 여러개를 매치할 수도 있고 이러한 다양한 검색방법이 필요로 되지는데 이를 정하는 것이 flag 이다.

그렇다면 flag의 종류는 뭐가 있을까? JS에서는 현재 6개의 flag 를 지원하고 있다. 이에 대해 각각 알아보자.

1. i 플래그 (insensitive)

i flag 는 대, 소문자 구분 없이 검색한다.
예시를 통해 알아보자.

const regex = /apple/i;

위와 같은 정규식에서 아래 문자열을 매치시킨다면?

apple Apple APPLE

그렇다면 대,소문자 구분이 없기 떄문에 모두 매치될 수 있다. 만약 i가 없다면, apple만 매치될 것이다.

2. g 플래그 (global)

g flag는 패턴과 일치하는 모든 것을 찾습니다.
문자열에서 한개만 찾는것이 아니라 이에 해당하는 모든 것을 찾고 싶다면 g flag를 사용해야 한다. 그렇지 않다면 이는 한개만 매치시키고 종료한다.

const regex = /apple/gi;

만약 이렇게 하고, 위의 문자열을 매치시킨다면 apple Apple APPLE 총 세개가 매치될 것이다.

const regex = /apple/i;

이렇게 한다면 apple 하나만 매치되고 끝난다. 한개가 아니라, 패턴이 들어가는 모든 것을 찾고 싶다면 이 g flag를 이용하면 된다.

3. m 플래그 (multiline)

이는 multiline mode를 의미하며, 여러줄을 탐색하고 싶을때 쓰는 플래그이다. 이를 쓰지 않는다면, 여러 줄이 아니라 한줄만 매치를 시도하고 종료한다. 문자열이 여러줄이며, 이를 모두 탐색하고 싶을때 이를 활용하면 된다.
추가적으로 앞서 설명한 ( ^ ) (문장의 시작), ( $ ) (문장의 끝)이 문장 기준으로 값을 매칭 시키는 것인데, 이를 활용하여 탐색하고 싶다면 이 플래그를 꼭 사용해야 한다. 그렇지 않으면 의도치 않는 결과가 나올 것이다.

4. s 플래그 (single line)

앞서 설명한 것 중에 . 가 있었다. 이는 모든 문자를 포함한다고 했다. 하지만 이때는 \n 은 포함하지 않는다. 이를 포함하고 싶다면 이 플래그를 사용해야 한다.

5. u 플래그 (unicode)

이 플래그는 유니코드를 지원해준다.
이를 사용할 시, surrogate.pair가 처리가 가능한다.

6. y 플래그 (sticky)

이는 문자 내 특정 위치에서 검색을 진행해준다.
index값 같은것을 통해 검색을 가능하게 해준다.

-> u플래그와 y플래그는 많이 쓰이지 않고, 내용이 어렵기 때문에 이러한 것이 있다 정도만 보고 넘어가자. 이후에 쓰는 기회가 있다면 그때 블로깅을 따로 하도록 하겠다.

여기서 중요한 것은 g , i , m 이다. 이 부분만 알아도 대부분 정규식은 세울 수 있다.




정리

이번 시간에는 정규식에 대해 알아보았다. 배우면서 느꼈던 점이 덧셈, 뺄셈 같이 개념 자체는 어렵지 않다. 하지만 이를 총 종합해서 정규식을 만들어야 되기 때문에 그 부분에서 많이 헷갈릴 수 있을 것이라고 생각한다. 개념에 대해 숙지가 끝났다면 난 이제 다 알아 가 아니라, 정규식과 관련한 문제를 많이 접하고, 이를 많이 풀어봐야 좋다.
수학 문제를 풀때도 개념을 배우는 것보다, 개념을 활용하여 문제를 푸는 것이 중요한 것처럼 말이다.


코딩 테스트를 풀다보면, 이 정규식을 통해서 문자열을 쉽게 처리하는 경우가 많다. 코테를 풀때, 이러한 정규식을 활용하는 것을 추천한다. 이렇게 되면 문제가 매우 적은 코드로 많은 일을 해낼 수 있다.



참고

1.MDN Web Docs 공식문서
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions
2. 드림코딩 github
https://github.com/dream-ellie/regex

profile
집돌이 FE개발자의 노트

0개의 댓글