정규표현식이 필요한 순간
회원가입 폼을 만든다고 가정해보자. 이메일, 전화번호, 비밀번호 입력값이 올바른지 검증해야 한다.
이걸 if문으로 처리하면 어떻게 될까.
if (pw.length >= 8) {
if (hasUpper(pw)) {
if (hasLower(pw)) {
if (hasDigit(pw)) {
if (hasSymbol(pw)) {
// 여기까지 와야 통과다
}
}
}
}
}조건이 복잡해질수록 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|b | a 또는 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
| 표현 | 의미 |
|---|---|
. | 줄바꿈을 제외한 모든 문자 |
\d | 숫자 0에서 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,}$/ |
돌아보며
마케터가 정규표현식을 배우는 이유는 개발자가 되기 위해서가 아니다.
데이터를 직접 다룰 수 있어야 진단이 빠르고, 커뮤니케이션이 정확해진다.
처음에는 외계어처럼 보이지만, 자주 쓰이는 패턴 몇 가지만 익혀두면 실무에서 쓸 수 있는 순간이 생각보다 많이 온다.