Toolypet
블로그로 돌아가기
Dev

정규식 마스터하기 2026 - 패턴별 실전 예제 총정리

이메일, URL, 전화번호 검증부터 복잡한 텍스트 파싱까지. 실무에서 바로 사용 가능한 정규식 패턴과 작동 원리를 코드와 함께 알아봅니다.

Toolypet Team

Toolypet Team

Development Team

7 분 읽기

정규식 마스터하기 2026

"정규식은 어렵다"는 말, 맞습니다. 하지만 한 번 익히면 텍스트 처리 시간을 90% 줄일 수 있습니다.

이 가이드에서는 실무에서 가장 많이 사용되는 정규식 패턴을 예제와 함께 정리합니다.


정규식 기초

기본 문법

패턴설명예시
.모든 문자 (1개)a.c → "abc", "a1c"
*0개 이상ab*c → "ac", "abc", "abbc"
+1개 이상ab+c → "abc", "abbc"
?0개 또는 1개colou?r → "color", "colour"
^문자열 시작^Hello
$문자열 끝world$
\d숫자 [0-9]\d{3} → "123"
\w단어 문자 [a-zA-Z0-9_]\w+
\s공백 문자\s+

문자 클래스

[abc]     - a, b, c 중 하나
[^abc]    - a, b, c 제외
[a-z]     - a부터 z까지
[A-Z]     - A부터 Z까지
[0-9]     - 0부터 9까지
[a-zA-Z]  - 모든 영문자

수량자

{n}       - 정확히 n개
{n,}      - n개 이상
{n,m}     - n개 이상 m개 이하
*         - 0개 이상 ({0,})
+         - 1개 이상 ({1,})
?         - 0 또는 1개 ({0,1})

그룹과 캡처

(abc)     - 캡처 그룹
(?:abc)   - 비캡처 그룹
(?<name>abc) - 명명된 그룹
\1        - 첫 번째 그룹 역참조

실전 패턴: 유효성 검증

이메일 주소

// 기본 패턴
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

// 테스트
emailRegex.test('user@example.com');  // true
emailRegex.test('invalid-email');      // false

패턴 분석:

^                     - 시작
[a-zA-Z0-9._%+-]+     - 로컬 파트 (1자 이상)
@                     - @ 기호
[a-zA-Z0-9.-]+        - 도메인 (1자 이상)
\.                    - . (이스케이프)
[a-zA-Z]{2,}          - TLD (2자 이상)
$                     - 끝

URL

const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;

// 테스트
urlRegex.test('https://example.com');           // true
urlRegex.test('https://sub.example.com/path');  // true
urlRegex.test('invalid url');                   // false

전화번호 (한국)

// 휴대폰
const mobileRegex = /^01[016789]-?\d{3,4}-?\d{4}$/;

// 일반 전화
const phoneRegex = /^0\d{1,2}-?\d{3,4}-?\d{4}$/;

// 테스트
mobileRegex.test('010-1234-5678');  // true
mobileRegex.test('01012345678');    // true

비밀번호 강도

// 최소 8자, 대/소문자, 숫자, 특수문자 포함
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;

// 패턴 분석
// (?=.*[a-z])   - 소문자 최소 1개 (전방탐색)
// (?=.*[A-Z])   - 대문자 최소 1개
// (?=.*\d)      - 숫자 최소 1개
// (?=.*[@$!%*?&]) - 특수문자 최소 1개
// {8,}          - 8자 이상

신용카드 번호

// Visa
const visaRegex = /^4[0-9]{12}(?:[0-9]{3})?$/;

// MasterCard
const mastercardRegex = /^5[1-5][0-9]{14}$/;

// 모든 카드 (하이픈 허용)
const cardRegex = /^\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}$/;

실전 패턴: 텍스트 추출

HTML 태그 내용 추출

const html = '<div class="title">Hello World</div>';

// 태그 내용 추출
const contentRegex = /<div[^>]*>(.*?)<\/div>/;
const match = html.match(contentRegex);
console.log(match[1]); // "Hello World"

// 모든 태그 제거
const noTags = html.replace(/<[^>]*>/g, '');
console.log(noTags); // "Hello World"

URL에서 도메인 추출

const url = 'https://www.example.com/path/page.html';

const domainRegex = /^(?:https?:\/\/)?(?:www\.)?([^/]+)/;
const domain = url.match(domainRegex)[1];
console.log(domain); // "example.com"

로그 파일 파싱

const logLine = '[2026-02-21 14:30:45] ERROR: Connection timeout at module.js:42';

const logRegex = /\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] (\w+): (.+) at (.+):(\d+)/;

const [, datetime, level, message, file, line] = logLine.match(logRegex);

console.log({
  datetime,  // "2026-02-21 14:30:45"
  level,     // "ERROR"
  message,   // "Connection timeout"
  file,      // "module.js"
  line,      // "42"
});

CSV 파싱 (쉼표 구분)

const csvLine = 'John,"Doe, Jr.",30,"New York, NY"';

// 쉼표 분리 (따옴표 내 쉼표 무시)
const csvRegex = /(?:^|,)("(?:[^"]*(?:""[^"]*)*)"|[^,]*)/g;

const fields = [];
let match;
while ((match = csvRegex.exec(csvLine)) !== null) {
  fields.push(match[1].replace(/^"|"$/g, '').replace(/""/g, '"'));
}

console.log(fields); // ["John", "Doe, Jr.", "30", "New York, NY"]

실전 패턴: 검색과 치환

전화번호 포맷팅

const phone = '01012345678';

// 하이픈 추가
const formatted = phone.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
console.log(formatted); // "010-1234-5678"

금액 포맷팅

const amount = '1234567890';

// 천 단위 콤마
const formatted = amount.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
console.log(formatted); // "1,234,567,890"

마스킹

// 이메일 마스킹
const email = 'username@example.com';
const masked = email.replace(/(.{2})(.*)(@.*)/, '$1***$3');
console.log(masked); // "us***@example.com"

// 전화번호 마스킹
const phone = '010-1234-5678';
const maskedPhone = phone.replace(/(\d{3})-(\d{4})-(\d{4})/, '$1-****-$3');
console.log(maskedPhone); // "010-****-5678"

공백 정리

const text = '  Hello    World  ';

// 앞뒤 공백 제거 (trim)
const trimmed = text.replace(/^\s+|\s+$/g, '');

// 연속 공백을 하나로
const normalized = text.replace(/\s+/g, ' ').trim();
console.log(normalized); // "Hello World"

고급 기능

Lookahead (전방탐색)

// Positive Lookahead: (?=...)
// "foo" 다음에 "bar"가 오는 경우만 매칭
const regex = /foo(?=bar)/;
'foobar'.match(regex);  // ["foo"]
'foobaz'.match(regex);  // null

// Negative Lookahead: (?!...)
// "foo" 다음에 "bar"가 오지 않는 경우만 매칭
const regex2 = /foo(?!bar)/;
'foobaz'.match(regex2); // ["foo"]
'foobar'.match(regex2); // null

Lookbehind (후방탐색)

// Positive Lookbehind: (?<=...)
// "$" 앞에 있는 숫자
const priceRegex = /(?<=\$)\d+/g;
'$100 and $200'.match(priceRegex); // ["100", "200"]

// Negative Lookbehind: (?<!...)
// "$" 앞에 없는 숫자
const nonPriceRegex = /(?<!\$)\d+/g;
'$100 and 200'.match(nonPriceRegex); // ["200"]

Named Groups (명명된 그룹)

const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = '2026-02-21'.match(dateRegex);

console.log(match.groups.year);  // "2026"
console.log(match.groups.month); // "02"
console.log(match.groups.day);   // "21"

Non-Greedy (비탐욕적)

const html = '<div>Hello</div><div>World</div>';

// Greedy (기본): 가능한 많이 매칭
/<div>.*<\/div>/.exec(html)[0];
// "<div>Hello</div><div>World</div>"

// Non-Greedy: 가능한 적게 매칭
/<div>.*?<\/div>/.exec(html)[0];
// "<div>Hello</div>"

언어별 구현

JavaScript

// 생성 방법
const regex1 = /pattern/flags;
const regex2 = new RegExp('pattern', 'flags');

// 메서드
regex.test(str);        // boolean
str.match(regex);       // 배열 또는 null
str.replace(regex, replacement);
str.split(regex);
regex.exec(str);        // 상세 매칭 정보

// 플래그
// g: 전역 검색
// i: 대소문자 무시
// m: 멀티라인
// s: dotAll (. 이 줄바꿈도 매칭)
// u: 유니코드

Python

import re

# 컴파일
pattern = re.compile(r'pattern', re.IGNORECASE)

# 메서드
re.match(pattern, string)   # 시작부터 매칭
re.search(pattern, string)  # 전체에서 검색
re.findall(pattern, string) # 모든 매칭 리스트
re.sub(pattern, repl, string) # 치환

# 예시
emails = re.findall(r'[\w.+-]+@[\w.-]+\.\w+', text)
cleaned = re.sub(r'\s+', ' ', text).strip()

Go

import "regexp"

// 컴파일
re := regexp.MustCompile(`\d+`)

// 메서드
re.MatchString(s)          // bool
re.FindString(s)           // 첫 매칭
re.FindAllString(s, -1)    // 모든 매칭
re.ReplaceAllString(s, r)  // 치환

// 예시
numbers := re.FindAllString("a1b2c3", -1)
// ["1", "2", "3"]

성능 최적화

컴파일된 정규식 재사용

// ❌ 느림: 매번 컴파일
function validate(email) {
  return /^[\w.+-]+@[\w.-]+\.\w+$/.test(email);
}

// ✅ 빠름: 한 번 컴파일
const emailRegex = /^[\w.+-]+@[\w.-]+\.\w+$/;
function validate(email) {
  return emailRegex.test(email);
}

비캡처 그룹 사용

// ❌ 불필요한 캡처
const regex = /(https?):\/\/(www\.)?(.+)/;

// ✅ 필요 없는 그룹은 비캡처
const regex = /(?:https?):\/\/(?:www\.)?(.+)/;

재앙적 역추적 방지

// ❌ 위험: (a+)+ 패턴
const bad = /^(a+)+$/;
'aaaaaaaaaaaaaaaaaaaaaa!'.match(bad); // 매우 느림

// ✅ 안전: 원자 그룹 또는 소유적 수량자
// JavaScript에서는 구조 변경으로 해결
const good = /^a+$/;

디버깅 팁

Regex Tester 활용

  1. 패턴 입력
  2. 테스트 문자열 입력
  3. 매칭 결과 하이라이트 확인
  4. 캡처 그룹 확인

단계별 검증

// 복잡한 패턴을 단계별로 검증
const parts = [
  '^',                    // 시작
  '[a-zA-Z0-9._%+-]+',    // 로컬 파트
  '@',                    // @
  '[a-zA-Z0-9.-]+',       // 도메인
  '\\.',                  // .
  '[a-zA-Z]{2,}',         // TLD
  '$',                    // 끝
];

const emailRegex = new RegExp(parts.join(''));

FAQ

Q1: . vs \. 차이는?

A: .는 모든 문자(와일드카드), \.는 문자 그대로의 점입니다.

Q2: * vs + 차이는?

A: *는 0개 이상, +는 1개 이상입니다.

  • ab*c → "ac", "abc", "abbc"
  • ab+c → "abc", "abbc" ("ac"는 매칭 안 됨)

Q3: 대소문자 무시는?

A: 플래그 i를 사용하세요.

  • JavaScript: /pattern/i
  • Python: re.IGNORECASE

Q4: 줄바꿈도 .으로 매칭하려면?

A: s 플래그 (dotAll) 사용하세요.

  • JavaScript: /pattern/s
  • Python: re.DOTALL

Q5: 이스케이프가 필요한 문자는?

A: \ ^ $ . | ? * + ( ) [ ] { } 이 문자들은 \로 이스케이프하세요.


마무리

정규식 핵심:

  1. 기초 문법: ., *, +, ?, [], ()
  2. 메타 문자: \d, \w, \s, ^, $
  3. 수량자: {n}, {n,}, {n,m}
  4. 고급 기능: Lookahead, Lookbehind, Named Groups

연습만이 답입니다. Regex Tester에서 실시간으로 테스트해보세요.


관련 도구

도구용도
Regex Tester정규식 테스트 및 디버깅
JSON FormatterJSON 포맷팅
정규식Regex패턴매칭개발JavaScriptPython

저자 소개

Toolypet Team

Toolypet Team

Development Team

The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.

Web DevelopmentCSS ToolsDeveloper ToolsSEOSecurity