🔍 Regex Pattern

📖 Regex Quick Reference

. - Any character except newline
\d - Digit (0-9)
\w - Word character (a-z, A-Z, 0-9, _)
\s - Whitespace
^ - Start of line
$ - End of line
* - 0 or more
+ - 1 or more
? - 0 or 1
{n} - Exactly n times
[abc] - Any of a, b, or c
() - Capture group

📖 정규표현식(Regex)이란?

🔤 정규표현식 (Regular Expression)

정규표현식(Regex 또는 RegExp)은 문자열에서 특정 패턴을 찾거나 검색, 치환하기 위한 강력한 도구입니다. 문자, 숫자, 특수문자의 조합으로 패턴을 정의하여 텍스트 처리를 자동화할 수 있습니다. 대부분의 프로그래밍 언어와 텍스트 에디터에서 지원하며, 데이터 검증, 파싱, 텍스트 추출 등에 널리 사용됩니다.

정규표현식 예시:
/^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-z]{2,}$/

위 패턴은 이메일 주소를 검증하는 정규표현식입니다.

💡 정규표현식 사용 사례

  • 데이터 검증: 이메일, 전화번호, URL, 비밀번호 형식 검증
  • 텍스트 검색: 로그 파일에서 특정 패턴 찾기, 코드에서 함수명 추출
  • 문자열 치환: 여러 개의 공백을 하나로, 날짜 형식 변환
  • 웹 스크래핑: HTML에서 이메일 주소, 전화번호 추출
  • 구문 분석: CSV 파싱, URL 파라미터 추출
  • 입력 필터링: 사용자 입력에서 특수문자 제거, 숫자만 추출
  • 라우팅: 웹 프레임워크에서 URL 패턴 매칭

🔧 기본 문법

📌 일반 문자
  • abc - "abc" 문자열과 정확히 일치
  • 123 - "123" 숫자 문자열과 일치
  • . - 임의의 한 문자 (줄바꿈 제외)
🔢 문자 클래스
  • \d - 숫자 [0-9]
  • \D - 숫자가 아닌 문자
  • \w - 단어 문자 [a-zA-Z0-9_]
  • \W - 단어 문자가 아닌 것
  • \s - 공백 문자 (스페이스, 탭, 줄바꿈)
  • \S - 공백이 아닌 문자
📏 수량자 (Quantifiers)
  • * - 0회 이상 반복
  • + - 1회 이상 반복
  • ? - 0회 또는 1회
  • {n} - 정확히 n회
  • {n,} - n회 이상
  • {n,m} - n회 이상 m회 이하
🎯 앵커 (Anchors)
  • ^ - 문자열 시작
  • $ - 문자열 끝
  • \b - 단어 경계
  • \B - 단어 경계가 아닌 곳
🎭 그룹과 범위
  • [abc] - a, b, c 중 하나
  • [^abc] - a, b, c가 아닌 것
  • [a-z] - a부터 z까지
  • (abc) - 캡처 그룹
  • (?:abc) - 비캡처 그룹
  • a|b - a 또는 b
🚩 플래그 (Flags)
  • g - 전역 검색 (모든 매칭 찾기)
  • i - 대소문자 구분 안 함
  • m - 다중행 모드
  • s - . 이 줄바꿈도 매칭
  • u - 유니코드 모드

📝 자주 사용하는 정규표현식 패턴

📧 이메일 주소
/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/

예: user@example.com

📱 전화번호 (한국)
/^01[0-9]-?\d{3,4}-?\d{4}$/

예: 010-1234-5678, 01012345678

🌐 URL
/^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/

예: https://www.example.com

🔐 비밀번호 (강력)
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/

최소 8자, 대소문자, 숫자, 특수문자 포함

💳 신용카드 번호
/^\d{4}-?\d{4}-?\d{4}-?\d{4}$/

예: 1234-5678-9012-3456

🆔 주민등록번호 (한국)
/^\d{6}-?[1-4]\d{6}$/

예: 990101-1234567

📅 날짜 (YYYY-MM-DD)
/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/

예: 2026-01-02

🕐 시간 (HH:MM)
/^([01]\d|2[0-3]):([0-5]\d)$/

예: 14:30

🎨 HEX 색상 코드
/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/

예: #FF5733, #F00

🌍 IP 주소 (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]?)$/

예: 192.168.0.1

📦 버전 번호 (Semantic)
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/

예: 1.2.3

🔗 HTML 태그
/<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/

예: <div>content</div>

🎓 고급 기법

🔮 Lookahead & Lookbehind
  • (?=...) - 긍정형 전방탐색 (뒤에 ... 가 있어야 함)
  • (?!...) - 부정형 전방탐색 (뒤에 ... 가 없어야 함)
  • (?<=...) - 긍정형 후방탐색 (앞에 ... 가 있어야 함)
  • (?<!...) - 부정형 후방탐색 (앞에 ... 가 없어야 함)
예시:
/\d+(?= dollars)/

"100 dollars"에서 "100"만 매칭 (dollars는 제외)

🎯 Named Capture Groups

(?<name>...) - 캡처 그룹에 이름 부여

예시:
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/

날짜에서 year, month, day를 명시적으로 추출

🔄 Backreference

\1, \2, ... - 이전 캡처 그룹 참조

예시:
/(\w+)\s+\1/

"hello hello" 같은 중복 단어 찾기

⚡ Greedy vs Lazy
  • *, +, ? - Greedy (최대한 많이 매칭)
  • *?, +?, ?? - Lazy (최소한만 매칭)
예시:
/<.+>/  vs  /<.+?>/

"<div>hello</div>"에서 전자는 전체, 후자는 각 태그만 매칭

❓ 자주 묻는 질문 (FAQ)

Q: 정규표현식을 어떻게 테스트하나요?

A: 위의 Regex Tester 도구를 사용하거나, 각 프로그래밍 언어의 정규표현식 함수를 사용하세요. JavaScript: str.match(/pattern/), Python: re.search(r'pattern', str). 온라인 도구(regex101.com, regexr.com)도 유용합니다.

Q: 정규표현식의 성능은 어떤가요?

A: 대부분의 경우 매우 빠르지만, 백트래킹(backtracking)이 많이 발생하는 복잡한 패턴은 느릴 수 있습니다. 특히 (a+)+, (a*)* 같은 중첩된 수량자는 "Catastrophic Backtracking"을 유발할 수 있으니 주의하세요. 가능하면 간단하고 명확한 패턴을 사용하세요.

Q: 정규표현식으로 HTML/XML을 파싱할 수 있나요?

A: 권장하지 않습니다. HTML/XML은 중첩 구조를 가진 복잡한 언어이므로 정규표현식으로 완벽하게 파싱하기 어렵습니다. 간단한 패턴 추출은 가능하지만, 복잡한 파싱은 전용 파서(DOMParser, BeautifulSoup, lxml 등)를 사용하세요.

Q: 정규표현식에서 특수문자를 어떻게 이스케이프하나요?

A: 백슬래시(\)를 사용하여 이스케이프합니다. 예: \., \*, \+, \?, \[, \], \(, \), \{, \}, \\. 모든 특수문자를 이스케이프하려면: str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')

Q: 정규표현식으로 이메일을 완벽하게 검증할 수 있나요?

A: 이론적으로는 가능하지만 실용적이지 않습니다. RFC 5322 표준을 완전히 따르는 정규표현식은 매우 복잡합니다. 대부분의 경우 간단한 패턴으로 기본 검증하고, 실제 이메일 발송을 통해 최종 확인하는 것이 좋습니다.

Q: 정규표현식 플래그는 무엇인가요?

A: 플래그는 정규표현식의 동작 방식을 변경하는 옵션입니다. /pattern/gi처럼 패턴 뒤에 붙입니다. g(global): 모든 매칭 찾기, i(case-insensitive): 대소문자 구분 안 함, m(multiline): ^와 $가 각 줄의 시작/끝과 매칭, s(dotall): . 이 줄바꿈도 매칭.

Q: 정규표현식을 배우기 어렵나요?

A: 기본 문법은 간단하지만, 복잡한 패턴을 작성하려면 연습이 필요합니다. 처음에는 간단한 패턴부터 시작하고, 필요할 때마다 새로운 문법을 배우는 것이 좋습니다. 온라인 튜토리얼, 대화형 도구(regexone.com), 치트시트를 활용하세요.

💡 정규표현식 작성 팁

  • 단순하게 시작: 복잡한 패턴보다 여러 개의 간단한 패턴을 조합하는 것이 읽기 쉽고 유지보수하기 좋음
  • 테스트 케이스: 매칭되어야 할 예시와 매칭되지 않아야 할 예시를 모두 테스트
  • 주석 사용: 복잡한 패턴은 주석으로 설명 (일부 언어에서 (?#comment) 또는 verbose 모드 지원)
  • 비캡처 그룹: 캡처가 필요 없는 그룹은 (?:...) 사용으로 성능 개선
  • 앵커 활용: ^$로 전체 문자열 매칭 보장
  • 도구 활용: regex101.com, regexr.com 같은 시각화 도구로 패턴 이해
  • 에러 처리: 잘못된 정규표현식은 예외를 발생시키므로 try-catch 사용
  • 보안: 사용자 입력을 정규표현식에 직접 사용하지 말고 이스케이프 처리

⚠️ 주의사항

  • 복잡한 중첩 패턴은 "Catastrophic Backtracking"으로 성능 문제 유발 가능
  • 정규표현식만으로 완벽한 검증은 어려움 - 추가 로직과 병행 사용 권장
  • .은 기본적으로 줄바꿈을 매칭하지 않음 (s 플래그 필요)
  • 그룹 캡처(())는 메모리를 사용하므로 필요 없으면 비캡처 그룹 사용
  • 언어마다 정규표현식 문법이 약간씩 다를 수 있음 (PCRE, POSIX, ECMAScript 등)
  • 사용자 입력을 정규표현식으로 직접 사용하면 ReDoS(Regular Expression Denial of Service) 공격 위험
  • 한글, 이모지 등 유니코드 처리 시 u 플래그 필요 (JavaScript)

💻 프로그래밍 언어별 정규표현식

JavaScript
// 생성
const regex1 = /pattern/gi;
const regex2 = new RegExp('pattern', 'gi');

// 테스트
regex.test('string');           // true/false
'string'.match(/pattern/g);     // 배열 또는 null
'string'.replace(/old/g, 'new'); // 치환
'string'.split(/,\s*/);         // 분할
Python
import re

# 검색
re.search(r'pattern', string)     # Match 객체 또는 None
re.match(r'pattern', string)      # 문자열 시작부터
re.findall(r'pattern', string)    # 모든 매칭
re.sub(r'old', 'new', string)     # 치환

# 컴파일 (재사용 시 성능 향상)
pattern = re.compile(r'pattern')
pattern.search(string)
Java
import java.util.regex.*;

// 패턴 생성
Pattern pattern = Pattern.compile("pattern");
Matcher matcher = pattern.matcher("string");

// 검색
matcher.find();      // 다음 매칭 찾기
matcher.matches();   // 전체 문자열 매칭
matcher.group();     // 매칭된 문자열

// 치환
String result = string.replaceAll("old", "new");
PHP
// 검색
preg_match('/pattern/', $string, $matches);
preg_match_all('/pattern/', $string, $matches);

// 치환
preg_replace('/old/', 'new', $string);

// 분할
preg_split('/,\s*/', $string);
Go
import "regexp"

// 컴파일
re := regexp.MustCompile(`pattern`)

// 검색
re.MatchString("string")           // true/false
re.FindString("string")            // 첫 매칭
re.FindAllString("string", -1)     // 모든 매칭

// 치환
re.ReplaceAllString("string", "new")

📚 추가 학습 리소스

📖 대화형 튜토리얼
  • RegexOne: 단계별 정규표현식 학습
  • RegexLearn: 게임처럼 배우는 정규표현식
  • HackerRank Regex: 연습 문제
🔧 도구 & 테스터
  • regex101.com: 상세한 설명과 디버깅
  • regexr.com: 시각적 표현과 치트시트
  • regexper.com: 정규표현식 시각화
📄 치트시트
  • MDN Web Docs: JavaScript 정규표현식 레퍼런스
  • Python re module: 공식 문서
  • Regular-Expressions.info: 종합 가이드