정규표현식(Regular Expression, Regex)은 처음 보면 암호 같지만, 익히고 나면 텍스트 처리의 강력한 무기가 됩니다. 이메일 유효성 검사, 전화번호 파싱, 로그 분석, 코드 리팩토링 등 수많은 곳에서 매일 쓰입니다.

기본 문법

// 리터럴 표기법
const pattern = /hello/;

// 생성자 표기법 (동적 패턴)
const pattern2 = new RegExp('hello');

// 플래그
/hello/i   // i: 대소문자 무시
/hello/g   // g: 전체 검색 (모든 매칭)
/hello/m   // m: 여러 줄 모드 (^, $가 각 줄에 적용)
/hello/s   // s: . 이 줄바꿈도 포함
/hello/gi  // 여러 플래그 조합

문자 클래스와 수량자

// 문자 클래스
/[abc]/    // a, b, c 중 하나
/[^abc]/   // a, b, c 를 제외한 문자
/[a-z]/    // 소문자 알파벳
/[0-9]/    // 숫자 (= \d)
/\d/       // 숫자
/\D/       // 숫자가 아닌 문자
/\w/       // 단어 문자 [a-zA-Z0-9_]
/\W/       // 단어 문자가 아닌 것
/\s/       // 공백 (스페이스, 탭, 줄바꿈)
/\S/       // 공백이 아닌 문자
/./        // 줄바꿈 제외 모든 문자

// 수량자
/a?/       // 0 또는 1개
/a*/       // 0개 이상
/a+/       // 1개 이상
/a{3}/     // 정확히 3개
/a{2,4}/   // 2~4개
/a{2,}/    // 2개 이상
/a+?/      // 최소 매칭 (게으른 수량자)

앵커와 그룹

// 앵커
/^hello/   // 문자열 시작
/hello$/   // 문자열 끝
/\bhello\b/ // 단어 경계

// 그룹
/(ab)+/    // 캡처 그룹: ab 반복
/(?:ab)+/  // 비캡처 그룹: 추출 불필요할 때
/(?<year>\d{4})/  // 명명된 캡처 그룹

// 예시: 날짜 파싱
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2026-04-07'.match(dateRe);
console.log(match.groups); // { year: '2026', month: '04', day: '07' }

JavaScript에서 사용하기

const str = 'Hello, World! Hello, Regex!';

// test — 매칭 여부 (boolean)
/hello/i.test(str);  // true

// match — 매칭 결과 배열
str.match(/hello/i);   // ['Hello', index: 0, ...]
str.match(/hello/gi);  // ['Hello', 'Hello']

// matchAll — 모든 매칭 반복자
for (const m of str.matchAll(/hello/gi)) {
  console.log(m[0], m.index);
}

// replace — 치환
str.replace(/hello/i, 'Hi');      // 'Hi, World! Hello, Regex!'
str.replace(/hello/gi, 'Hi');     // 'Hi, World! Hi, Regex!'

// replace with 함수
str.replace(/hello/gi, (match) => match.toUpperCase());

// split
'a,b,,c'.split(/,+/);  // ['a', 'b', 'c']

실무 패턴 모음

// 이메일 검증
const emailRe = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
emailRe.test('user@devlog.kr');  // true

// 한국 전화번호
const phoneRe = /^(010|011|016|017|018|019)-?\d{3,4}-?\d{4}$/;
phoneRe.test('010-1234-5678');  // true

// URL 파싱
const urlRe = /^(https?):\/\/([^/\s]+)(\/[^\s]*)?(\?[^\s#]*)?(#\S*)?$/;
const [, protocol, host, path] = 'https://devlog.kr/posts/regex'.match(urlRe);

// 비밀번호 검증 (8자 이상, 대/소문자, 숫자, 특수문자 포함)
const pwRe = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%]).{8,}$/;

// 16진수 색상 코드
const hexRe = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;
hexRe.test('#6891f8');  // true

// 마크다운 제목 파싱
const headingRe = /^(#{1,6})\s+(.+)$/m;
const [, level, title] = '## 정규표현식이란'.match(headingRe);
// level: '##', title: '정규표현식이란'

Lookahead & Lookbehind

// Positive Lookahead (?=...) — 뒤에 이게 있을 때
/\d+(?=원)/  // '1000원'에서 '1000' 매칭

// Negative Lookahead (?!...) — 뒤에 이게 없을 때
/\d+(?!원)/  // '1000$'에서 매칭

// Positive Lookbehind (?<=...) — 앞에 이게 있을 때
/(?<=\$)\d+/  // '$100'에서 '100' 매칭

// 숫자 세 자리마다 콤마 삽입
function addCommas(n) {
  return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
addCommas(1234567);  // '1,234,567'
실전 팁
regex101.com 또는 regexr.com에서 실시간으로 패턴을 테스트하세요. 복잡한 정규표현식은 주석과 함께 명명된 그룹을 활용해 가독성을 높이세요. 이메일이나 URL 검증처럼 복잡한 케이스는 battle-tested 라이브러리(validator.js 등)를 사용하는 것이 안전합니다.