정규식(Regex) 사용법: 개발자를 위한 완전 가이드
정규식을 처음부터 배워보세요. 기본 문법, 문자 클래스, 수량자, 그룹, lookahead, lookbehind, 그리고 이메일, 전화번호, URL, IP를 위한 자주 쓰는 패턴을 실전 예제와 함께 정리했습니다.
정규식이란 무엇이며 어디에 쓰이는가
정규식(regex 또는 regexp)은 텍스트를 매우 정밀하게 찾고, 검증하고, 가공할 수 있게 해주는 검색 패턴입니다. 프로그래밍, 시스템 운영, 데이터 처리에서 기본 도구로 쓰입니다.
정규식은 본질적으로 검색 규칙을 정의하는 문자 시퀀스입니다. 한 줄의 regex만으로도, 일반 조건문으로는 수십 줄이 필요할 작업을 처리할 수 있습니다.
정규식의 대표적인 사용 사례:
- 데이터 검증: 이메일, 전화번호, URL, 우편번호 형식이 올바른지 확인
- 검색 및 치환: 긴 텍스트에서 특정 패턴을 찾아 바꾸기
- 데이터 추출: 비정형 텍스트에서 필요한 정보만 뽑아내기
- 로그 파싱: 서버와 애플리케이션 로그 분석
- 린팅과 포맷팅: 코드가 특정 규칙을 따르는지 검사
- 웹 라우팅: Express, Django, Rails 같은 프레임워크에서 URL 규칙 정의
Regex는 거의 모든 프로그래밍 언어에서 지원됩니다. JavaScript, Python, Java, C#, PHP, Ruby, Go, Rust는 물론 grep, sed, awk 같은 CLI 도구에서도 널리 사용됩니다.
읽으면서 바로 연습하고 싶다면 새 탭에서 regex 테스트 도구를 열어 보세요.
기본 문법: 리터럴 문자와 메타문자
Regex 문법은 크게 두 가지로 나뉩니다. 리터럴 문자는 그대로 매칭되고, 메타문자는 특별한 의미를 가집니다.
리터럴 문자:
알파벳, 숫자, 대부분의 기호는 기본적으로 문자 그대로 매칭됩니다. 예를 들어 cat 패턴은 텍스트에서 "cat"이라는 단어를 찾습니다.
핵심 메타문자:
| 메타문자 | 의미 | 예시 | 매칭 결과 |
|---|---|---|---|
. | 임의의 문자 하나(줄바꿈 제외) | c.t | "cat", "cot", "c3t" |
^ | 문자열/줄의 시작 | ^Hello | "Hello world"의 시작 부분 |
$ | 문자열/줄의 끝 | world$ | "Hello world"의 끝 부분 |
* | 0회 이상 반복 | ab*c | "ac", "abc", "abbc", "abbbc" |
+ | 1회 이상 반복 | ab+c | "abc", "abbc" ("ac" 제외) |
? | 0회 또는 1회(선택) | colou?r | "color", "colour" |
| | 또는(OR) | cat|dog | "cat" 또는 "dog" |
\ | 이스케이프 | \. | 리터럴 점 문자 |
메타문자 이스케이프하기:
메타문자를 일반 문자로 검색하려면 앞에 \를 붙여야 합니다. 예를 들면:
\.점 문자 자체를 찾습니다\*별표를 찾습니다\?물음표를 찾습니다\(와\)는 괄호를 찾습니다\\는 역슬래시를 찾습니다
실전 예시: "price: $9.99"라는 문자열을 찾으려면 price: \$9\.99라고 써야 합니다.
문자 클래스와 미리 정의된 클래스
문자 클래스를 사용하면 패턴의 특정 위치에서 어떤 문자들이 허용되는지 정의할 수 있습니다.
대괄호 [ ] 로 만드는 사용자 정의 클래스:
| 패턴 | 의미 | 매칭 예시 |
|---|---|---|
[abc] | a, b, c 중 하나 | "a", "b", "c" |
[a-z] | 소문자 하나 | "a", "m", "z" |
[A-Z] | 대문자 하나 | "A", "M", "Z" |
[0-9] | 숫자 하나 | "0", "5", "9" |
[a-zA-Z] | 영문자 하나 | "a", "Z", "m" |
[a-zA-Z0-9] | 영문 또는 숫자 | "a", "3", "Z" |
[^abc] | a, b, c를 제외한 문자 | "d", "1", "Z" |
[^0-9] | 숫자가 아닌 문자 | "a", "!", " " |
자주 쓰는 축약 클래스:
아래 표기는 반복적으로 자주 쓰이는 조합을 간단히 표현한 것입니다.
| 축약형 | 동등한 표현 | 의미 |
|---|---|---|
\d | [0-9] | 숫자 하나 |
\D | [^0-9] | 숫자가 아닌 문자 |
\w | [a-zA-Z0-9_] | 단어 문자(영문, 숫자, 밑줄) |
\W | [^a-zA-Z0-9_] | 단어 문자가 아닌 문자 |
\s | [\t\n\r\f\v ] | 공백 문자 |
\S | [^\t\n\r\f\v ] | 공백이 아닌 문자 |
\b | (직접 대응 없음) | 단어 경계 |
단어 경계 (\b):
\b는 완전한 단어를 찾을 때 특히 유용합니다. \bcat\b는 "cat"은 찾지만 "caterpillar"나 "scat"은 찾지 않습니다. 이는 문자를 소비하지 않는 위치 앵커입니다.
실전 예시: 문자열이 영문자, 숫자, 하이픈만 포함하는지 검증하려면 ^[a-zA-Z0-9-]+$를 사용할 수 있습니다.
수량자와 반복 제어
수량자는 앞의 요소가 몇 번 나타나야 하는지 지정합니다.
기본 수량자:
| 수량자 | 의미 | 예시 | 매칭 결과 |
|---|---|---|---|
* | 0회 이상 | \d* | "" , "5", "123", "99999" |
+ | 1회 이상 | \d+ | "5", "123", "99999" |
? | 0회 또는 1회 | -?\d+ | "42", "-42" |
{n} | 정확히 n회 | \d{4} | "2026", "1234" |
{n,} | n회 이상 | \d{2,} | "12", "123", "1234" |
{n,m} | n회 이상 m회 이하 | \d{2,4} | "12", "123", "1234" |
탐욕적(greedy) 수량자와 게으른(lazy) 수량자:
기본적으로 수량자는 탐욕적이어서 가능한 한 긴 문자열을 잡으려 합니다. 수량자 뒤에 ?를 붙이면 게으른 방식이 되어 가능한 한 짧은 결과를 먼저 매칭합니다.
<.*>는 첫 번째<부터 마지막>까지 먹어버릴 수 있습니다<.*?>는 HTML 태그를 하나씩 더 안전하게 매칭할 때 자주 씁니다
실전 사용 예:
전화번호가 10자리 또는 11자리인지 검사하려면 ^\d{10,11}$
사용자 이름이 3자 이상 16자 이하인지 검사하려면 ^[a-zA-Z0-9_]{3,16}$
그룹, 캡처, 그리고 backreference
그룹은 regex의 여러 부분을 논리적으로 묶어 줍니다. 이를 통해 일부를 캡처하거나, 선택지를 묶거나, 수량자를 여러 문자에 한꺼번에 적용할 수 있습니다.
주요 그룹 종류:
| 문법 | 종류 | 용도 |
|---|---|---|
(...) | 캡처 그룹 | 매칭된 텍스트를 저장 |
(?:...) | 비캡처 그룹 | 그룹화만 하고 저장하지 않음 |
(?<name>...) | 이름 있는 그룹 | 그룹에 이름을 붙여 읽기 쉽게 만듦 |
캡처 그룹 예시:
YYYY-MM-DD 형식 날짜에서 연, 월, 일을 추출하려면:
(\d{4})-(\d{2})-(\d{2})
- 그룹 1: 연도 (예: "2026")
- 그룹 2: 월 (예: "03")
- 그룹 3: 일 (예: "16")
JavaScript에서 "2026-03-16".match(/(\d{4})-(\d{2})-(\d{2})/) 는 배열을 반환하며, [1]은 "2026", [2]는 "03", [3]은 "16"입니다.
이름 있는 그룹:
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
JavaScript에서는 match.groups.year, match.groups.month, match.groups.day 로 접근할 수 있습니다.
Backreference:
앞서 캡처한 텍스트를 뒤에서 다시 참조할 수 있게 해줍니다.
(\w+)\s+\1는 "the the", "is is" 같은 중복 단어를 찾습니다(['"])(.*?)\1는 따옴표 안 텍스트를 찾으며 여는 따옴표와 닫는 따옴표가 같은 종류인지까지 확인합니다
그룹 안의 대안 패턴:
(https?|ftp):// 는 "http://", "https://", "ftp://"와 매칭됩니다.
이런 패턴은 regex 도구에서 실시간으로 시험해 볼 수 있습니다.
Lookahead와 lookbehind: 위치 단언
Lookahead 와 lookbehind 는 현재 위치의 앞이나 뒤에 특정 패턴이 있는지를 문자를 소비하지 않고 확인하는 단언입니다. 복잡한 검증에서 매우 강력합니다.
대표적인 4가지 단언:
| 문법 | 이름 | 의미 |
|---|---|---|
(?=pattern) | 긍정형 lookahead | 뒤쪽이 해당 패턴과 반드시 일치해야 함 |
(?!pattern) | 부정형 lookahead | 뒤쪽이 해당 패턴과 일치하면 안 됨 |
(?<=pattern) | 긍정형 lookbehind | 앞쪽이 해당 패턴과 반드시 일치해야 함 |
(?<!pattern) | 부정형 lookbehind | 앞쪽이 해당 패턴과 일치하면 안 됨 |
예시 1: 강한 비밀번호 검증
대문자 하나 이상, 소문자 하나 이상, 숫자 하나 이상, 전체 길이 8자 이상을 요구하는 패턴:
^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$
(?=.*[A-Z]): 대문자 최소 1개 필요(?=.*[a-z]): 소문자 최소 1개 필요(?=.*\d): 숫자 최소 1개 필요.{8,}: 길이는 8자 이상
예시 2: 통화 기호 없이 가격만 추출
(?<=\$)\d+\.\d{2}
"The price is $29.99 and shipping is $5.00"라는 문장에서 "$"를 제외한 "29.99"와 "5.00"만 잡아냅니다.
예시 3: 특정 패턴이 뒤따르지 않는 단어 찾기
\w+(?!\s*:)
뒤에 콜론이 붙지 않는 단어를 찾습니다. "key: value" 구조에서 키와 값을 구분할 때 유용합니다.
예시 4: 마이너스 부호가 앞에 없는 숫자
(?<!-)\b\d+\b
양수만 찾고 음수는 제외합니다. "5 -3 8 -12"에서는 "5"와 "8"만 매칭됩니다.
호환성 참고: Lookbehind는 모든 regex 엔진이 지원하지 않습니다. JavaScript는 ES2018부터 지원하며, Python, Java, C#, .NET도 잘 지원합니다. 일부 엔진은 고정 길이 lookbehind만 허용합니다.
자주 쓰는 패턴: 이메일, 전화번호, URL, IP
아래는 가장 많이 쓰이는 검증 패턴을 위한 실용적인 정규식 예시입니다. 다만 이메일처럼 복잡한 형식은 어떤 regex도 100% 완벽할 수 없으므로, 운영 환경에서는 서버 측 검증과 함께 사용하는 것이 좋습니다.
1. 이메일 (실용적 검증):
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
- 로컬 파트: 영문자, 숫자, 점, 하이픈, 밑줄, %, + 허용
- @: 필수 구분자
- 도메인: 영문자, 숫자, 점, 하이픈 허용
- TLD: 최소 2글자
- 유효 예시: user@example.com, first.last@company.co.uk
2. 국제 전화번호 (E.164 형식):
^\+?[1-9]\d{1,14}$
- 앞의 + 는 선택 사항
- 첫 숫자는 1~9여야 하며 0으로 시작할 수 없음
- 총 길이는 최대 15자리
- 유효 예시: +821012345678, 447911123456
3. URL (HTTP/HTTPS):
^https?:\/\/[\w.-]+(?:\.[a-zA-Z]{2,})(?:\/[\w.~:/?#\[\]@!$&'()*+,;=-]*)?$
- 프로토콜: http:// 또는 https://
- 도메인: 영문숫자, 점, 하이픈 허용
- TLD: 최소 2글자
- 경로: 선택 사항이며 일반적인 URL 문자 허용
4. IPv4 주소:
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$
- 점으로 구분된 4개의 옥텟
- 각 옥텟 값은 0~255 범위
- 유효: 192.168.1.1, 10.0.0.1, 255.255.255.0
- 무효: 256.1.1.1, 192.168.1.999
5. ISO 날짜 형식 (YYYY-MM-DD):
^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$
- 연도: 4자리 숫자
- 월: 01-12
- 일: 01-31
- 02-30 같은 실제로 없는 날짜까지는 검증하지 못하므로 추가 로직이 필요합니다
6. CSS 색상 hex 값:
^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
- 지원 형식: #RGB, #RRGGBB, #RRGGBBAA
- 유효 예시: #fff, #FF5733, #FF573380
이 패턴들은 regex 테스트 도구에서 직접 검증하고 다듬을 수 있습니다. 이런 패턴이 들어 있는 JSON을 확인할 때는 JSON 검증기도 함께 활용하세요.
플래그, 성능, 그리고 모범 사례
Regex를 제대로 다루려면 플래그(flag, modifier)를 이해하고 성능 문제와 유지보수 부담을 줄이는 습관을 익혀야 합니다.
자주 쓰는 플래그:
| 플래그 | 이름 | 효과 |
|---|---|---|
g | Global | 첫 번째가 아니라 모든 매칭 결과를 찾음 |
i | Case insensitive | 대소문자를 구분하지 않음 |
m | Multiline | ^ 와 $ 가 각 줄의 시작과 끝에도 매칭됨 |
s | Dotall | 점 . 이 줄바꿈 문자도 포함함 |
u | Unicode | 유니코드 문자를 온전히 처리함 |
JavaScript에서는 /pattern/flags 형태로 씁니다. 예: /hello world/gi
Python에서는 re.compile(r'pattern', re.IGNORECASE | re.MULTILINE) 처럼 사용합니다.
성능 관련 모범 사례:
- 재앙적 백트래킹을 피하세요:
(a+)+$같은 패턴은 엔진이 지수적으로 많은 경우를 시도하게 만들 수 있습니다. 이것이 ReDoS 문제로 이어질 수 있으므로 가능하면 possessive quantifier나 atomic group을 고려하세요 - 패턴을 구체적으로 쓰세요: 문자만 기대한다면
.+보다[a-z]+가 낫습니다. 패턴이 구체적일수록 대체로 더 빠릅니다 - 앵커를 활용하세요:
^와$는 엔진이 어디서 시작하고 끝내야 하는지 알려주므로 불필요한 탐색을 줄입니다 - 비캡처 그룹을 우선 고려하세요: 결과를 저장할 필요가 없다면
(?:...)가 더 적절합니다 - 엣지 케이스를 테스트하세요: 빈 문자열, 긴 입력, 예상 밖 문자까지 포함해 검증해야 운영에서 안전합니다
유지보수를 위한 팁:
- 긴 regex는 주석을 달거나 여러 부분으로 나눠서 문서화하세요
- 너무 복잡한 규칙은 regex 하나로 끝내려 하지 말고 일반 코드와 조합하세요
- 긍정 사례와 부정 사례 모두 테스트 케이스로 남겨 두세요
패턴을 안전하게 실험하려면 regex 테스트 도구를, 관련 데이터 구조를 확인하려면 JSON 검증기를 사용하면 됩니다.
이 도구를 사용해 보세요:
도구 열기→자주 묻는 질문
처음 regex를 배우는 사람은 무엇부터 익혀야 하나요?
리터럴 문자, 문자 클래스, 앵커(^와 $), 기본 수량자(*, +, ?, {n})부터 이해하는 것이 좋습니다. 이 기초가 잡히면 그룹, backreference, lookahead/lookbehind 같은 고급 개념도 훨씬 쉽게 익힐 수 있습니다.
하나의 regex가 모든 프로그래밍 언어에서 똑같이 동작하나요?
완전히 같지는 않습니다. 기본 개념은 비슷하지만, 각 regex 엔진마다 lookbehind 지원 여부, Unicode 처리, 확장 문법에서 차이가 있습니다. 사용 중인 언어나 라이브러리의 문서를 함께 확인해야 합니다.
이메일 검증은 regex 하나만으로 충분한가요?
기본 형식 검증에는 유용하지만 그것만으로는 충분하지 않습니다. 실제 서비스에서는 도메인 확인, MX 레코드 검사, 인증 메일 발송 같은 서버 측 검증도 함께 고려해야 합니다.
왜 어떤 regex는 매우 느리게 실행되나요?
대개 과도한 백트래킹 때문입니다. 중첩 반복이나 애매한 패턴은 엔진이 너무 많은 경우를 다시 시도하게 만듭니다. 패턴을 더 구체적으로 쓰고, 앵커를 넣고, 불필요한 캡처를 줄이면 성능이 나아집니다.
HTML 파싱에 regex를 써도 되나요?
아주 단순하고 통제된 경우에는 일부 패턴 매칭 정도는 가능하지만, 일반적으로는 권장되지 않습니다. HTML은 중첩 구조와 예외가 많아서 전용 파서를 쓰는 편이 훨씬 안전합니다.
regex를 가장 빨리 잘하게 되는 방법은 무엇인가요?
개념을 배운 직후 바로 실습하는 것이 가장 빠릅니다. 이메일, URL, 날짜, 로그, 폼 검증 같은 실제 사례를 regex tester에서 반복해서 테스트하면 실력이 빠르게 늘어납니다.