728x90
정규표현식(Regular Expression, 줄여서 Regex 또는 RegExp)은 문자열의 패턴을 표현하는 특수한 문자열입니다. 텍스트에서 특정 패턴을 검색하고, 추출하고, 치환하는 데 사용되는 강력한 도구입니다.
- 복잡한 문자열 패턴을 간결하게 표현
- 거의 모든 프로그래밍 언어에서 지원
- 검색, 유효성 검사, 추출, 치환 등에 활용
300x250
기본 문법과 구성 요소
메타 문자(Meta Characters)
문자 | 설명 | 예시 |
---|---|---|
. |
임의의 한 문자 | a.c → abc, a1c, a@c |
* |
앞 문자가 0개 이상 | ab*c → ac, abc, abbc |
+ |
앞 문자가 1개 이상 | ab+c → abc, abbc (ac는 불가) |
? |
앞 문자가 0개 또는 1개 | ab?c → ac, abc |
^ |
문자열의 시작 | ^Hello → Hello로 시작하는 문자열 |
$ |
문자열의 끝 | world$ → world로 끝나는 문자열 |
[] |
문자 클래스 | [abc] → a, b, c 중 하나 |
[^] |
부정 문자 클래스 | [^abc] → a, b, c가 아닌 문자 |
| |
OR 연산자 | cat|dog → cat 또는 dog |
() |
그룹화 | (ab)+ → ab, abab, ababab |
특수 이스케이프 시퀀스
시퀀스 | 설명 | 예시 |
---|---|---|
\d |
숫자 [0-9] | \d{3} → 123, 456 |
\D |
숫자가 아닌 문자 | \D+ → abc, xyz |
\w |
단어 문자 [a-zA-Z0-9_] | \w+ → hello, test_123 |
\W |
단어 문자가 아닌 문자 | \W+ → @#$, !!! |
\s |
공백 문자 | \s+ → 스페이스, 탭, 개행 |
\S |
공백이 아닌 문자 | \S+ → hello, 123 |
\b |
단어 경계 | \bword\b → 독립된 word |
\n |
개행 문자 | - |
\t |
탭 문자 | - |
수량자(Quantifiers)
수량자 | 설명 | 예시 |
---|---|---|
{n} |
정확히 n개 | \d{4} → 1234 |
{n,} |
n개 이상 | \d{2,} → 12, 123, 1234 |
{n,m} |
n개 이상 m개 이하 | \d{2,4} → 12, 123, 1234 |
*? |
0개 이상 (최소 매칭) | <.*?> → HTML 태그 |
+? |
1개 이상 (최소 매칭) | .+? → 최소 매칭 |
분야별 활용 사례
웹 개발 / 프론트엔드
이메일 유효성 검사
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const isValid = emailRegex.test("user@example.com");
전화번호 형식 검사
// 한국 휴대폰 번호
const phoneRegex = /^01[0-9]-?\d{3,4}-?\d{4}$/;
// 010-1234-5678, 01012345678 모두 매칭
// 국제 전화번호
const intlPhoneRegex = /^\+\d{1,3}[-.\s]?\(?\d{1,4}\)?[-.\s]?\d{1,4}[-.\s]?\d{1,9}$/;
URL 추출
const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi;
const urls = text.match(urlRegex);
백엔드 / 서버 개발
로그 파일 분석 (Apache/Nginx)
import re
# Apache 액세스 로그 파싱
log_pattern = r'(\d+\.\d+\.\d+\.\d+) - - \[(.*?)\] "(.*?)" (\d+) (\d+)'
log_line = '192.168.1.1 - - [10/Oct/2023:13:55:36 +0700] "GET /index.html HTTP/1.1" 200 2326'
match = re.match(log_pattern, log_line)
if match:
ip, timestamp, request, status_code, size = match.groups()
SQL 인젝션 방지
# 위험한 SQL 패턴 감지
dangerous_patterns = [
r"(\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION)\b)",
r"(--|\#|\/\*|\*\/)",
r"(\bOR\b\s*\d+\s*=\s*\d+)",
r"(\bAND\b\s*\d+\s*=\s*\d+)"
]
def check_sql_injection(user_input):
for pattern in dangerous_patterns:
if re.search(pattern, user_input, re.IGNORECASE):
return True
return False
API 엔드포인트 라우팅
# Flask/Django 스타일 라우팅
routes = [
(r'^/users/(\d+)$', 'get_user'),
(r'^/posts/(\d+)/comments$', 'get_comments'),
(r'^/api/v(\d+)/(.+)$', 'api_handler')
]
데이터 처리 / 분석
CSV 데이터 정제
# 쉼표가 포함된 CSV 필드 처리
csv_pattern = r'(?:^|,)("(?:[^"]+|"")*"|[^,]*)'
# 날짜 형식 표준화
date_patterns = {
r'(\d{4})/(\d{2})/(\d{2})': r'\1-\2-\3', # YYYY/MM/DD → YYYY-MM-DD
r'(\d{2})/(\d{2})/(\d{4})': r'\3-\1-\2', # MM/DD/YYYY → YYYY-MM-DD
r'(\d{2})-(\d{2})-(\d{4})': r'\3-\1-\2' # MM-DD-YYYY → YYYY-MM-DD
}
텍스트 마이닝
# 해시태그 추출
hashtag_pattern = r'#[가-힣a-zA-Z0-9_]+'
# 멘션 추출
mention_pattern = r'@[a-zA-Z0-9_]+'
# 한글 단어 추출
korean_word_pattern = r'[가-힣]+'
설정 파일 / 구성 관리
.env 파일 파싱
# KEY=VALUE 형식 파싱
env_pattern = r'^([A-Z_]+)=(.*)$'
def parse_env_file(content):
env_vars = {}
for line in content.split('\n'):
match = re.match(env_pattern, line)
if match:
key, value = match.groups()
env_vars[key] = value.strip('"\'')
return env_vars
nginx.conf 파싱
# location 블록 추출
location_pattern = r'location\s+(.*?)\s*\{([^}]*)\}'
# upstream 서버 추출
upstream_pattern = r'server\s+([^;]+);'
보안 / 유효성 검사
비밀번호 강도 검사
const passwordRules = {
minLength: /.{8,}/,
hasUpperCase: /[A-Z]/,
hasLowerCase: /[a-z]/,
hasNumber: /\d/,
hasSpecialChar: /[!@#$%^&*(),.?":{}|<>]/
};
function validatePassword(password) {
return Object.entries(passwordRules).every(([rule, regex]) =>
regex.test(password)
);
}
XSS 방지
// 위험한 HTML 태그 제거
const dangerousTagsRegex = /<script[^>]*>.*?<\/script>|<iframe[^>]*>.*?<\/iframe>/gi;
const sanitizedHtml = userInput.replace(dangerousTagsRegex, '');
파일 처리 / 시스템 관리
파일명 패턴 매칭
# Bash에서 find와 함께 사용
find . -regex '.*\.\(jpg\|png\|gif\)$'
# Python에서 파일 필터링
import re
import os
def find_files_by_pattern(directory, pattern):
regex = re.compile(pattern)
matched_files = []
for root, dirs, files in os.walk(directory):
for file in files:
if regex.match(file):
matched_files.append(os.path.join(root, file))
return matched_files
# 예: 날짜가 포함된 백업 파일 찾기
backup_files = find_files_by_pattern('.', r'backup_\d{8}_\d{6}\.tar\.gz$')
정규표현식 손쉽게 생성하는 방법
온라인 도구 활용
1. Regex101 (https://regex101.com)
- 실시간 매칭 결과 확인
- 상세한 설명 제공
- 여러 언어의 정규식 엔진 지원
- 저장 및 공유 기능
2. RegExr (https://regexr.com)
- 시각적 표현
- 치트시트 제공
- 커뮤니티 패턴 라이브러리
3. Regex Visualizer (https://regexper.com)
- 정규식을 시각적 다이어그램으로 변환
- 복잡한 패턴 이해에 유용
AI 도구 활용
# ChatGPT나 Claude에게 요청하는 예시
"""
다음 조건을 만족하는 정규표현식을 만들어주세요:
- 한국 주민등록번호 형식 (######-#######)
- 앞 6자리는 생년월일 (YYMMDD)
- 뒤 7자리 중 첫 번째는 1-4 중 하나
"""
# 결과: ^\d{6}-[1-4]\d{6}$
패턴 빌더 라이브러리
JavaScript - VerbalExpressions
const VerEx = require('verbal-expressions');
const urlRegex = VerEx()
.startOfLine()
.then('http')
.maybe('s')
.then('://')
.maybe('www.')
.anythingBut(' ')
.endOfLine();
Python - re-builder
from rebuilder import ReBuilder
rb = ReBuilder()
email_pattern = (rb
.start()
.one_or_more.word()
.literal('@')
.one_or_more.word()
.literal('.')
.between(2, 4).letters()
.end()
.build()
)
단계별 구축 전략
1단계: 기본 패턴 작성
// 목표: 이메일 주소 매칭
// 시작: 기본 구조
const step1 = /.+@.+\..+/;
2단계: 세부 규칙 추가
// 허용 문자 지정
const step2 = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
3단계: 경계 조건 추가
// 시작과 끝 명시
const step3 = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
4단계: 예외 처리
// 특수 케이스 고려
const final = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/i;
실전 팁과 최적화
성능 최적화
1. 불필요한 캡처 그룹 피하기
// 나쁜 예
/(https?):\/\/(www\.)?([a-z]+\.[a-z]+)/
// 좋은 예 (비캡처 그룹 사용)
/(?:https?):\/\/(?:www\.)?([a-z]+\.[a-z]+)/
2. 구체적인 문자 클래스 사용
// 나쁜 예
/.*/ // 모든 문자
// 좋은 예
/[^,]*/ // 쉼표를 제외한 문자
3. 앵커 사용으로 검색 범위 제한
// 나쁜 예
/admin/ // 문자열 전체 검색
// 좋은 예
/^admin/ // 시작 부분만 검색
가독성 향상
1. 명명된 캡처 그룹 사용
// ES2018+
const dateRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = dateRegex.exec('2023-10-15');
console.log(match.groups.year); // 2023
2. 주석과 공백 활용 (x 플래그)
# Python
pattern = re.compile(r"""
^ # 시작
(?P<protocol>https?) # 프로토콜
:// # 구분자
(?P<domain>[^/]+) # 도메인
(?P<path>/.*)? # 경로 (선택적)
$ # 끝
""", re.VERBOSE)
디버깅 전략
1. 단계별 테스트
function debugRegex(pattern, testCases) {
testCases.forEach(testCase => {
const match = pattern.test(testCase);
console.log(`"${testCase}": ${match ? '✓' : '✗'}`);
});
}
2. 부분 패턴 분리
// 복잡한 패턴을 작은 단위로 분리
const protocolPattern = /https?/;
const domainPattern = /[a-zA-Z0-9.-]+/;
const pathPattern = /\/[^ ]*/;
// 조합
const urlPattern = new RegExp(
`^${protocolPattern.source}://${domainPattern.source}${pathPattern.source}?$`
);
언어별 정규표현식 차이점
JavaScript vs Python
// JavaScript
const pattern = /\d+/g; // 전역 플래그
const matches = text.match(pattern);
// Python
import re
pattern = r'\d+'
matches = re.findall(pattern, text)
Java 특수성
// 이스케이프 문자 이중 처리
Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
// 여러 줄 모드
Pattern multiline = Pattern.compile("^test$", Pattern.MULTILINE);
PHP 구분자
// 다양한 구분자 사용 가능
preg_match('/pattern/', $text);
preg_match('#pattern#', $text);
preg_match('~pattern~', $text);
자주 사용되는 패턴 모음
한국어 관련
// 한글만
/^[가-힣]+$/
// 한글과 공백
/^[가-힣\s]+$/
// 한국 우편번호 (새 형식)
/^\d{5}$/
// 한국 사업자등록번호
/^\d{3}-\d{2}-\d{5}$/
웹 관련
// 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]?)$/
// 헥스 컬러 코드
/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
// 유튜브 비디오 ID
/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&\n?#]+)/
데이터 유효성
// 신용카드 번호 (간단)
/^\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}$/
// ISBN-13
/^(?:ISBN(?:-13)?:?\ ?)?(?=[0-9]{13}$|(?=(?:[0-9]+[-\ ]){4})[-\ 0-9]{17}$)97[89][-\ ]?[0-9]{1,5}[-\ ]?[0-9]+[-\ ]?[0-9]+[-\ ]?[0-9]$/
// MAC 주소
/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/
정규표현식 사용 시 주의사항
1. 과도한 복잡성 피하기
- 너무 복잡한 정규식은 유지보수가 어려움
- 필요시 여러 개의 간단한 패턴으로 분리
2. 성능 고려
- 백트래킹이 많이 발생하는 패턴 주의
- 큰 텍스트에서는 정규식 대신 파싱 라이브러리 고려
3. 보안 이슈
- 사용자 입력을 정규식 패턴으로 사용 금지 (ReDoS 공격)
- 유효성 검사는 정규식만으로 충분하지 않을 수 있음
4. 국제화 고려
- 유니코드 문자 처리
- 다양한 언어와 문자 체계 지원
정규표현식은 강력한 도구이지만, 적절히 사용해야 합니다. 간단한 문자열 처리는 내장 함수로, 복잡한 파싱은 전용 파서로 처리하는 것이 좋을 수 있습니다. 정규표현식은 그 중간 영역에서 빛을 발합니다. 항상 가독성과 유지보수성을 고려하여 작성하고, 충분한 테스트를 통해 예상치 못한 경우를 대비하세요.
728x90
그리드형(광고전용)
댓글