정규 표현식: 예제와 함께하는 실용 가이드
· 12분 읽기
정규 표현식(regex)은 개발자 도구 상자에서 가장 강력한 도구 중 하나이지만, 종종 오해받거나 완전히 회피되곤 합니다. 사용자 입력 검증, 로그 파일 파싱, 텍스트 데이터 변환 등 어떤 작업을 하든, 정규 표현식은 문자열의 패턴을 매칭하는 간결하고 효율적인 방법을 제공합니다.
이 종합 가이드는 정규 표현식 기초부터 고급 기법까지, 프로젝트에서 즉시 사용할 수 있는 실용적인 예제와 함께 안내합니다. 마지막에는 정규 표현식이 어떻게 작동하는지뿐만 아니라, 언제 그리고 왜 사용해야 하는지 이해하게 될 것입니다.
목차
정규 표현식이란 무엇이며 왜 알아야 할까요?
정규 표현식은 검색 패턴을 정의하는 문자 시퀀스입니다. 텍스트에서 패턴 매칭을 위해 특별히 설계된 미니 언어라고 생각하면 됩니다. 정확한 문자열을 검색하는 대신, 정규 표현식을 사용하면 "모든 이메일 주소" 또는 "이 형식의 모든 전화번호"와 같은 패턴을 설명할 수 있습니다.
정규 표현식은 거의 모든 프로그래밍 언어와 많은 명령줄 도구에서 지원됩니다. 구문을 한 번 배우면 JavaScript와 Python부터 grep과 sed까지 어디서나 적용할 수 있습니다.
일반적인 사용 사례는 다음과 같습니다:
- 사용자 입력 검증(이메일, 전화번호, 비밀번호)
- 텍스트에서 데이터 추출(로그 파싱, 콘텐츠 스크래핑)
- 검색 및 바꾸기 작업(코드 리팩토링, 데이터 정리)
- URL 라우팅 및 패턴 매칭
- 구문 강조 및 어휘 분석
프로 팁: 정규 표현식은 강력하지만 항상 올바른 도구는 아닙니다. HTML이나 JSON과 같은 복잡한 파싱 작업에는 전용 파서를 사용하세요. 정규 표현식은 잘 정의된 비교적 간단한 패턴에 가장 적합합니다.
정규 표현식 기초: 구성 요소
모든 정규 표현식 패턴은 기본 구성 요소로 만들어집니다. 더 복잡한 패턴으로 넘어가기 전에 이러한 핵심 요소를 이해하는 것이 필수적입니다.
리터럴 문자
가장 간단한 정규 표현식은 단순히 리터럴 텍스트입니다. cat 패턴은 텍스트에서 정확히 "cat" 문자열과 매칭됩니다. 대부분의 영숫자 문자는 직접 자신과 매칭됩니다.
메타문자
특정 문자는 정규 표현식에서 특별한 의미를 가집니다. 이를 메타문자라고 하며 다음을 포함합니다: . ^ $ * + ? { } [ ] \ | ( )
이러한 문자를 리터럴로 매칭하려면 백슬래시로 이스케이프해야 합니다. 예를 들어, \.는 리터럴 마침표와 매칭됩니다.
점 와일드카드
점 .은 가장 기본적인 와일드카드로, 개행 문자를 제외한 모든 단일 문자와 매칭됩니다. a.c 패턴은 "abc", "a1c", "a-c"와 매칭되지만 "ac"(사이에 문자 없음) 또는 "a\nc"(개행)와는 매칭되지 않습니다.
| 패턴 | 매칭 | 예제 |
|---|---|---|
. |
모든 문자 (개행 제외) | a.c는 abc, a1c, a-c와 매칭 |
\d |
모든 숫자 [0-9] | \d{3}는 123, 456과 매칭 |
\w |
단어 문자 [a-zA-Z0-9_] | \w+는 hello, user_1과 매칭 |
\s |
공백 (스페이스, 탭, 개행) | \s+는 스페이스, 탭과 매칭 |
\D |
숫자가 아닌 문자 | \D+는 abc, xyz와 매칭 |
\W |
단어 문자가 아닌 문자 | \W+는 !@#, 스페이스와 매칭 |
\S |
공백이 아닌 문자 | \S+는 모든 보이는 텍스트와 매칭 |
대문자 버전(\D, \W, \S)은 소문자 버전의 반대임을 주목하세요. 이것은 정규 표현식 구문의 일반적인 패턴입니다.
수량자: 반복 제어
수량자는 패턴이 몇 번 반복되어야 하는지 지정합니다. 반복하려는 요소 뒤에 배치되며 유연한 패턴을 만드는 데 기본적입니다.
기본 수량자
| 수량자 | 의미 | 예제 |
|---|---|---|
* |
0회 이상 | ab*c는 ac, abc, abbc, abbbc와 매칭 |
+ |
1회 이상 | ab+c는 abc, abbc와 매칭 (ac는 아님) |
? |
0회 또는 1회 (선택적) | colou?r는 color, colour와 매칭 |
{n} |
정확히 n회 | \d{4}는 2026, 1999와 매칭 |
{n,} |
n회 이상 | \d{3,}는 123, 1234, 12345와 매칭 |
{n,m} |
n회에서 m회 사이 | \d{2,4}는 12, 123, 1234와 매칭 |
탐욕적 vs. 게으른 매칭
기본적으로 수량자는 탐욕적입니다. 가능한 한 많은 텍스트와 매칭합니다. 이는 HTML 태그와 같은 패턴을 매칭할 때 예상치 못한 결과를 초래할 수 있습니다.
// 탐욕적 매칭
const text = "<div>Hello</div><div>World</div>";
const greedy = /<.*>/;
// 매칭: "<div>Hello</div><div>World</div>" (전체 문자열!)
// 게으른 매칭
const lazy = /<.*?>/;
// 매칭: "<div>" (첫 번째 닫는 괄호에서 멈춤)
수량자 뒤에 ?를 추가하면 게으른 (비탐욕적) 매칭이 됩니다. 게으른 수량자는 패턴을 만족하면서 가능한 한 적은 텍스트와 매칭합니다.
빠른 팁: 구분 기호(따옴표, 괄호, 태그) 사이의 콘텐츠를 매칭할 때는 일반적으로 게으른 수량자가 원하는 것입니다. 너무 많이 매칭하지 않도록 .* 대신 .*?를 사용하세요.
문자 클래스와 단축키
문자 클래스를 사용하면 특정 집합의 모든 문자와 매칭할 수 있습니다. 대괄호를 사용하여 정의되며 유연한 패턴을 만드는 데 매우 유용합니다.
기본 문자 클래스
// 모든 모음과 매칭
/[aeiou]/
// 모든 숫자와 매칭
/[0-9]/
// 모든 소문자와 매칭
/[a-z]/
// 모든 문자와 매칭 (대소문자 구분 없음)
/[a-zA-Z]/
// 영숫자 문자와 매칭
/[a-zA-Z0-9]/
부정 문자 클래스
문자 클래스의 시작 부분에 ^를 사용하여 부정합니다. 나열된 문자를 제외한 모든 문자와 매칭합니다.
// 숫자가 아닌 모든 문자와 매칭
/[^0-9]/
// 모음이 아닌 모든 문자와 매칭
/[^aeiou]/
// 스페이스나 탭을 제외한 모든 문자와 매칭
/[^ \t]/
클래스 내의 특수 문자
대부분의 메타문자는 문자 클래스 내에서 특별한 의미를 잃습니다. ., *, +, ?를 이스케이프 없이 포함할 수 있습니다. 그러나 특정 위치에서는 여전히 ], \, ^, -를 이스케이프해야 합니다.
// 마침표 또는 쉼표와 매칭
/[.,]/
// 하이픈과 매칭 (이스케이프하거나 시작/끝에 배치)
/[-a-z]/ 또는 /[a-z-]/
// 닫는 괄호와 매칭 (반드시 이스케이프)
/[\]]/
그룹과 캡처
그룹은 두 가지 주요 목적을 제공합니다: 여러 문자에 수량자를 적용할 수 있게 하고, 나중에 사용하기 위해 매칭된 텍스트를 캡처합니다.
캡처 그룹
괄호는 매칭된 텍스트를 기억하는 캡처 그룹을 만듭니다. 이는 문자열에서 데이터를 추출하는 데 필수적입니다.
// 날짜 구성 요소 추출
const datePattern = /(\d{4})-(\d{2})-(\d{2})/;
const match = "2026-03-29".match(datePattern);
// match[0]: "2026-03-29" (전체 매칭)
// match[1]: "2026" (첫 번째 그룹)
// match[2]: "03" (두 번째 그룹)
// match[3]: "29" (세 번째 그룹)
명명된 캡처 그룹
명명된 그룹은 정규 표현식을 더 읽기 쉽게 만들고 코드를 더 유지보수하기 쉽게 만듭니다. 그룹을 번호로 참조하는 대신 설명적인 이름을 부여합니다.
// 명명된 그룹 구문: (?<name>pattern)
const datePattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = "2026-03-29".match(datePattern);
// 이름으로 접근
console.log(match.groups.year); // "2026"
console.log(match.groups.month); // "03"
console.log(match.groups.day); // "29"
비캡처 그룹
때로는 수량자나 교체를 위해 그룹화가 필요하지만 텍스트를 캡처하고 싶지 않을 때가 있습니다. 비캡처 그룹은 (?:...) 구문을 사용합니다.
// 그룹을 만들지 않고 프로토콜 캡처
/(?:https?|ftp):\/\/([a-z.]+)/
// 이것은 하나의 캡처 그룹만 생성합니다 (도메인)
// 프로토콜 그룹 (?:https?|ftp)은 캡처하지 않습니다
비캡처 그룹은 캡처 그룹보다 빠르고 메모리를 덜 사용합니다. 캡처된 텍스트가 필요하지 않을 때 사용하세요.
역참조
역참조를 사용하면 이전 그룹에서 캡처한 것과 동일한 텍스트와 매칭할 수 있습니다. 이는 반복되는 단어를 찾거나 쌍을 이루는 구분 기호를 매칭하는 데 유용합니다.
// 반복되는 단어 찾기
/\b(\w+)\s+\1\b/
// "the the" 또는 "hello hello"와 매칭
// 쌍을 이루는 따옴표 매칭
/(['"])(.*?)\1/
// "hello" 또는 'world'와 매칭하지만 "mixed'와는 매칭하지 않음
교체
파이프 | 연산자는 교체를 생성합니다. 하나의 패턴 또는 다른 패턴과 매칭합니다. 논리적 OR과 같습니다.
// cat, dog, 또는 bird와 매칭
/cat|dog|bird/
// 일반적인 파일 확장자와 매칭
/\.(jpg|jpeg|png|gif|webp)$/i
// Mr., Mrs., Ms., 또는 Dr.와 매칭
/(?:Mr|Mrs|Ms|Dr)\./
앵커와 경계
앵커는 문자와 매칭하지 않고 문자열의 위치와 매칭합니다. 패턴이 특정 위치에 나타나도록 보장하는 데 필수적입니다.
문자열 앵커
^는 문자열의 시작과 매칭 (또는 다중 행 모드에서 줄의 시작)$는 문자열의 끝과 매칭 (또는 다중 행 모드에서 줄의 끝)
// "Hello"로 시작해야 함
/^Hello/
// "world"로 끝나야 함
/world$/
// 전체 문자열이 정확히 5자리 숫자여야 함
/^\d{5}$/
단어 경계
\b 앵커는 단어 경계와 매칭합니다. 단어 문자와 비단어 문자 사이의 위치입니다. 이는 전체 단어를 매칭하는 데 중요합니다.
// "cat"을 전체 단어로 매칭
/\bcat\b/
// 매칭: "cat", "the cat sat"
// 매칭하지 않음: "category", "scat"
// "pre"로 시작하는 단어와 매칭
/\bpre\w+/
// 매칭: "preview", "prepare", "prefix"
역 \B는 비단어 경계와 매칭합니다. 양쪽이 모두 단어 문자이거나 모두 비단어 문자인 위치입니다.
프로 팁: 전체 단어를 검색할 때는 항상 단어 경계를 사용하세요. 단어 경계가 없으면 "cat"을 검색할 때 "category"와 "concatenate"도 매칭됩니다. \bcat\b 패턴은 완전한 단어만 매칭하도록 보장합니다.
실제 사용을 위한 일반적인 패턴
다음은 일반적인 검증 및 추출 작업을 위한 실전 테스트를 거친 정규 표현식 패턴입니다. 이러한 패턴은 단순성과 실용적인 정확성의 균형을 맞춥니다.
| 패턴 유형 | 정규 표현식 | 참고 |
|---|---|---|
| 이메일 (간단) | ^[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}$ |
기본 검증에 적합 |
| 이메일 (RFC 준수) | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ |
더 엄격하고 널리 받아들여짐 |
| URL | ^https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/\S*)?$ |
기본 HTTP/HTTPS URL |
| IPv4 주소 | ^(?:\d{1,3}\.){3}\d{1,3}$ |
형식만, 범위 검증 안 함 |
| IPv4 (엄격) | ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ |
0-255 범위 검증 |
| 날짜 (YYYY-MM-DD) | ^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ |
ISO 8601 형식 |
| 시간 (24시간) | ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$ |
HH:MM 또는 HH:MM:SS |
| 전화번호 (미국) | ^\+?1?[-.\s]?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$ |
유연한 형식 |
| 16진수 색상 | ^#(?:[0-9a-fA-F]{3}){1,2}$ |
3자리 또는 6자리 16진수 코드 |
| 신용카드 | ^\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}$ |
형식만, 검증은 Luhn 사용 |
| 사용자명 | ^[a-zA-Z0-9_-]{3,16}$ |
3-16자, 영숫자 및 _ 와 - |
| 슬러그 | ^[a-z0-9]+(?:-[a-z0-9]+)*$ |
하이픈이 있는 URL 친화적 소문자 |
비밀번호 검증
비밀번호 검증은 여러 조건을 동시에 확인해야 합니다. 전방탐색 어서션을 사용하면 복잡한 로직 없이 이것이 가능합니다.
// 강력한 비밀번호: 8자 이상, 대문자, 소문자, 숫자, 특수 문자
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/
// 분석:
// (?=.*[a-z]) - 최소 하나의 소문자
// (?=.*[A-Z]) -