자바스크립트 교재 · 20편 / 26편

정규식 기초 — 이메일·전화번호 검증

메타 문자·플래그·그룹·자주 쓰는 패턴 한 번에.

중급 마지막읽는 시간 7분2026-05-17
정규식 패턴이 텍스트를 매치하는 도식과 그룹 캡처의 흐름

정규식(regex) 은 한 번 익히면 평생 쓰는 도구 — 텍스트에서 패턴을 찾고·추출하고·바꿉니다. 11편의 한 입 맛본 후, 20편에서 본격 기초를 정리. 메타 문자·플래그·그룹과 자주 쓰는 패턴들. 중급 파트의 마지막입니다.

정규식 만들기 — 두 가지 방법

// 리터럴 (가장 흔함)
const re1 = /hello/;

// RegExp 생성자 (동적 패턴)
const word = "hello";
const re2 = new RegExp(word);
const re3 = new RegExp(`\\d{${digitCount}}`);   // 동적 값 끼울 때

주요 메서드 — 사용 빈도순

const text = "전화: 010-1234-5678";
const re = /\d{3}-\d{4}-\d{4}/;

re.test(text);          // true   — 매치 여부 boolean
text.match(re);         // ["010-1234-5678"] — 첫 매치 (g 없으면)
text.matchAll(/\d+/g);  // 이터레이터 — 모든 매치 (그룹 포함)
text.replace(re, "[전화]");   // "전화: [전화]"
text.split(/\s+/);            // ["전화:", "010-1234-5678"]
text.search(re);              // 0 또는 -1 (위치)

플래그 5종

플래그의미
gglobal — 모든 매치 (한 번이 아니라)
iignore case — 대소문자 무시
mmultiline — ^$ 가 줄 단위
sdotAll — . 이 줄바꿈도 매치
uunicode — 이모지·코드포인트 안전
"Hello hello HELLO".match(/hello/gi);
// ["Hello", "hello", "HELLO"]

메타 문자 — 의미 있는 기호

패턴매치
.임의의 한 글자 (줄바꿈 제외)
\d숫자 [0-9]
\D숫자 아님
\w단어 문자 [A-Za-z0-9_]
\s공백 (스페이스·탭·줄바꿈)
\b단어 경계
^ $줄 시작 / 끝
[abc]a·b·c 중 하나
[^abc]a·b·c 가 아닌 것
[a-z]범위
a|ba 또는 b

수량자 — 몇 번 반복하나

패턴의미
?0 또는 1번 (옵션)
*0번 이상
+1번 이상
{n}정확히 n번
{n,}n번 이상
{n,m}n~m번
+?lazy — 가장 적게 매치 (기본은 greedy)

그룹과 캡처 — ()

// 위치 기반 그룹
const m = "2026-05-17".match(/^(\d{4})-(\d{2})-(\d{2})$/);
// m[0]="2026-05-17", m[1]="2026", m[2]="05", m[3]="17"

// 이름 있는 그룹 (?<name>...)
const m2 = "2026-05-17".match(/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/);
m2.groups.year;     // "2026"
m2.groups.month;    // "05"
m2.groups.day;      // "17"

// 비캡처 그룹 (?:...)
"hello world".replace(/(?:hello|hi) (\w+)/, "안녕 $1");
// "안녕 world"   ← 첫 그룹은 캡처 안 함

// 역참조 \1
"hello hello".match(/(\w+) \1/);   // 같은 단어 반복

자주 쓰는 패턴 7가지

// 1. 이메일 (대략) — 실제 RFC 5322 는 매우 복잡, 보통 이 정도면 충분
const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

// 2. 한국 전화번호 (010-1234-5678 또는 01012345678)
const phoneRe = /^01[0-9]-?\d{3,4}-?\d{4}$/;

// 3. URL
const urlRe = /^https?:\/\/[^\s]+$/;

// 4. 한국어만
const koreanRe = /^[가-힣]+$/;

// 5. 영숫자 + _ - 만 (slug)
const slugRe = /^[a-z0-9_-]+$/;

// 6. 카드 번호 분리 (1234567812345678 → 1234 5678 1234 5678)
"1234567812345678".replace(/(\d{4})(?=\d)/g, "$1 ");

// 7. 좋은 비밀번호 (대문자·소문자·숫자 각 1개 이상, 8자+)
const pwRe = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;

lookahead · lookbehind — 위치 기반 매칭

// (?=...) — 뒤따라야 함 (소비 안 함)
"abc123".match(/[a-z]+(?=\d)/);    // "abc" — 숫자 앞의 글자

// (?!...) — 뒤따르면 안 됨
"abc def".match(/abc(?! def)/);    // null

// (?<=...) — 앞에 있어야 함 (소비 안 함)
"$100".match(/(?<=\$)\d+/);        // "100"

// (?<!...) — 앞에 있으면 안 됨

replace + 함수 — 강력한 변환

// 매치마다 함수 호출
"hello world".replace(/\w+/g, m => m.toUpperCase());
// "HELLO WORLD"

// 그룹과 함께
"2026-05-17".replace(/(\d{4})-(\d{2})-(\d{2})/, (_, y, m, d) => `${y}년 ${+m}월 ${+d}일`);
// "2026년 5월 17일"

// 이름 있는 그룹
"a:1, b:2".replace(/(?<k>\w+):(?<v>\d+)/g, (...args) => {
  const { k, v } = args.at(-1);   // 마지막 인자가 groups
  return `${k}=${v}`;
});

안티패턴 / 주의 5가지

1. 이메일 정규식에 너무 정확히. RFC 완전 정확은 너무 복잡 → /^[^\s@]+@[^\s@]+\.[^\s@]+$/ 정도 + 실제로 인증 메일 보내 검증.

2. HTML 파싱. 정규식으로 HTML 파싱 절대 금지. DOMParser 또는 cheerio.

3. 백트래킹 폭주(ReDoS). (a+)+ 같은 중첩 수량자에 긴 입력 → 영겁의 시간. 사용자 입력 패턴 만들 때 주의.

4. g 플래그 + test 함정. regex.test() 가 g 플래그면 lastIndex 가 유지됨 → 같은 regex 인스턴스 재사용 시 다음 호출이 다른 위치부터. 매번 새로 만들거나 lastIndex 리셋.

5. 가독성. 5줄짜리 정규식은 6개월 뒤 자신도 못 읽음. 주석 모드 없는 JS 에서는 변수로 분해하거나 라이브러리(date-fns·zod) 사용.

21편 — 클로저 깊이 (고급 시작)

함수가 함수를 기억하는 메커니즘. 카운터 패턴부터 메모리 누수까지.

📚 쉽게 배우는 자바스크립트 교재
이전: 19편 모듈 · 현재: 20편 (중급 마지막) · 다음 → 21편 클로저 (고급 시작) · 진행: 20/26

© 2026 주나이테크(주) @JUNAITECH