정규표현식이 필요한 순간

회원가입 폼을 만든다고 해 보자. 이메일, 전화번호, 비밀번호가 제대로 들어왔는지 확인해야 한다.

이걸 if문으로 하나씩 처리하면 어떻게 될까.

if (pw.length >= 8) {
  if (hasUpper(pw)) {
    if (hasLower(pw)) {
      if (hasDigit(pw)) {
        if (hasSymbol(pw)) {
          // 여기까지 와야 통과다
        }
      }
    }
  }
}

조건이 늘수록 if문 안에 if문이 끝없이 들어간다. 비밀번호만 봐도 "영문 대소문자 포함, 숫자 포함, 특수문자 포함, 8자 이상"을 짜려는 순간 막막하다.

정규표현식은 같은 조건을 한 줄에 담는다.

/^(?=.*[A-Za-z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/.test(pw);

정규표현식이란

정규표현식은 정해진 규칙을 따르는 문자열들을 패턴 하나로 적는 형식 언어다. 문자열을 찾고 바꾸는 데 특화돼 있다.

/^[\w.+-]+@[\w-]+\.[\w.-]+$/

처음 보면 외계어 같다.

근데 어디에 쓰는지 알고 나면 얘기가 달라진다.

정규표현식을 꺼내는 상황

  • 저마다 다른 형식으로 저장된 전화번호를 뽑아내야 할 때
  • 사용자가 넣은 이메일, 휴대폰 번호, IP 주소가 맞는 형식인지 확인할 때
  • 코드에서 특정 변수 이름만 바꾸고, 그 변수가 들어간 함수는 건드리고 싶지 않을 때
  • 조건에 맞춰 문자열 속 공백이나 특수문자를 지울 때

쓰임새를 묶으면 검색과 치환 두 가지다.


정규표현식을 만드는 두 가지 방법

1) 리터럴 방식

var regex = /abc/;

패턴을 슬래시(/) 두 개 사이에 넣는 방식이다. 패턴이 안 바뀌는 상수라면 성능상 유리하다.

2) 객체 생성자 방식

var regex = new RegExp("abc");

RegExp 생성자에 패턴을 매개변수로 넘긴다. 패턴이 바뀔 수 있거나 사용자 입력에서 패턴을 받아 와야 할 때 쓴다.


자주 쓰는 메소드

메소드형태반환값
test()regex.test(str)매칭되면 true, 아니면 false
exec()regex.exec(str)첫 매칭 정보를 담은 배열, 없으면 null
match()str.match(regex)매칭된 문자열을 담은 배열
replace()str.replace(regex, 대체값)치환이 끝난 새 문자열
search()str.search(regex)첫 매칭 위치, 없으면 -1
split()str.split(regex)패턴 기준으로 쪼갠 배열

콘솔에 직접 쳐 보면 바로 보인다.

const regex = /marketer/;
 
regex.test("i am a marketer");    // true
"i am a marketer".search(regex);  // 7
"i am a marketer".replace(regex, "growth hacker");
// "i am a growth hacker"

플래그 (고급 검색)

  • g (global): 문자열 전체에서 매칭을 전부 찾는다
  • i (case insensitive): 대소문자를 가리지 않는다
  • m (multiline): 여러 줄에 걸쳐 찾는다
"Cat cat CAT".match(/cat/g);   // ["cat"]
"Cat cat CAT".match(/cat/gi);  // ["Cat", "cat", "CAT"]

정규표현식의 핵심은 패턴이다

1) Group and range

표현의미
(abc)괄호 안을 통째로 한 그룹으로 묶는다
(?:abc)그룹으로 묶지만 캡처는 하지 않는다
a|ba 또는 b
[abc]a, b, c 중 하나
[a-z]a부터 z 사이 문자 하나
[^abc]a, b, c를 뺀 나머지 문자

2) Quantifiers

표현의미
a+a가 1회 이상
a*a가 0회 이상
a?a가 0회 또는 1회
a{3}a가 정확히 3회
a{2,}a가 2회 이상
a{2,4}a가 2회 이상 4회 이하
a+?게으른 수량자. 가능한 한 짧게 매칭하고 멈춘다

3) Boundary-type

표현의미
^문자열 시작. m 플래그를 켜면 줄마다 시작
$문자열 끝. m 플래그를 켜면 줄마다 끝
\b단어 경계
\B단어 경계가 아닌 곳

4) Character classes

표현의미
.줄바꿈을 뺀 모든 문자
\d0에서 9까지 숫자
\D숫자 말고 다른 문자
\w영문자·숫자·언더스코어 중 하나
\W\w에 안 들어가는 문자
\s공백·탭·줄바꿈 같은 빈칸 문자
\S공백 말고 다른 문자

패턴 연습은 regexr.com에서 하면 편하다. 치는 동안 결과가 바로 보인다.


자주 쓰는 패턴

용도패턴
이메일/^[\w.+-]+@[\w-]+\.[\w.-]+$/
휴대폰 번호/^01[016789]-?\d{3,4}-?\d{4}$/
숫자만/^\d+$/
한글만/^[가-힣]+$/
날짜 YYYY-MM-DD/^\d{4}-\d{2}-\d{2}$/
URL/^https?:\/\/[^\s/$.?#].[^\s]*$/
모든 공백/\s/g
비밀번호 (영문·숫자·특수문자가 다 들어간 8자 이상)/^(?=.*[A-Za-z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/
2가지만드는 방법 (리터럴 / 생성자)
3가지자주 쓰는 플래그 (g / i / m)
4가지패턴 종류
검색+치환정규표현식이 하는 일

왜 배웠나

정규표현식은 데이터를 남에게 맡기지 않고 직접 들여다보려고 배웠다.
그래야 원인을 빨리 찾고 소통도 정확해진다.

처음엔 외계어 같아도 자주 쓰는 패턴 몇 개만 익혀 두면 실무에서 꺼낼 일이 생각보다 많다.