정규표현식이 필요한 순간
회원가입 폼을 만든다고 해 보자. 이메일, 전화번호, 비밀번호가 제대로 들어왔는지 확인해야 한다.
이걸 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|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,}$/ |
왜 배웠나
정규표현식은 데이터를 남에게 맡기지 않고 직접 들여다보려고 배웠다.
그래야 원인을 빨리 찾고 소통도 정확해진다.
처음엔 외계어 같아도 자주 쓰는 패턴 몇 개만 익혀 두면 실무에서 꺼낼 일이 생각보다 많다.