정규 표현식 개요
정규 표현식은 문자열 처리 전용 도메인 특화 언어로, 파이썬에서는 re 모듈을 통해 구현됩니다. 패턴은 바이트코드로 컴파일되며 C 기반 엔진에서 실행됩니다.
정규식 메타문자 의미
| 문자 | 의미 | 예시 패턴 | 매칭 예시 |
|---|---|---|---|
| . | 개행문자(\n) 제외 모든 문자 | a.c | abc, axc |
| \ | 이스케이프 처리 | a\.c | a.c |
| * | 0회 이상 반복 | ab*c | ac, abbc |
| + | 1회 이상 반복 | ab+c | abc, abbc |
| ? | 0회 또는 1회 | ab?c | ac, abc |
| ^ | 문자열 시작 | ^abc | abc |
| $ | 문자열 종료 | abc$ | abc |
| | | 또는 | abc|def | abc, def |
| {} | 반복 횟수 지정 | ab{2}c | abbc |
| [] | 문자 집합 | [ae]bc | abc, ebc |
| () | 그룹화 | (ab)+ | ab, abab |
이스케이프 문자 기능
- 메타문자 일반 문자 변환: \. → .
- 사전 정의 문자 집합: \d → 숫자
- 그룹 참조: \1 → 첫 번째 그룹
result = re.search(r'(min)(seo)haha\2','minseohahaseo').group()
print(result) # minseohahaseo
사전 정의 문자 집합
| 문자 | 의미 | 예시 |
|---|---|---|
| \d | [0-9] | a\dc → a1c |
| \D | 비숫자 | a\Dc → abc |
| \s | 공백 문자 | a\sc → a c |
| \w | [a-zA-Z0-9_] | a\wc → a1c |
| \b | 단어 경계 | \bcode\b → "code" |
고급 그룹화
| 패턴 | 의미 | 예시 |
|---|---|---|
| (?P<id>...) | 명명된 그룹 | (?P<num>\d) |
| (?P=id) | 명명된 그룹 참조 | (?P<num>\d)abc(?P=num) |
re 모듈 주요 함수
compile()
패턴을 정규식 객체로 컴파일
pattern = re.compile(r'\w*ing\w*')
text = "coding is interesting"
print(pattern.findall(text)) # ['coding', 'interesting']
match()
문자열 시작에서 패턴 매칭
print(re.match('py','python').group()) # py
search()
문자열 전체에서 첫 번째 매칭 검색
print(re.search('\d+','id:123').group()) # 123
findall()
모든 매칭 문자열 리스트 반환
print(re.findall(r'\d+','1a2b3c')) # ['1','2','3']
finditer()
매칭 객체 반복자 생성
matches = re.finditer(r'\d+','1a22b333')
for m in matches:
print(m.group(), m.span())
split()
패턴 기준 문자열 분할
print(re.split(r'\d+','a1b22c')) # ['a','b','c']
sub()
패턴 일치 부분 대체
print(re.sub(r'\s+', '-', 'a b c')) # a-b-c
subn()
대체 수행 및 횟수 반환
print(re.subn(r'\d','X','a1b2')) # ('aXbX', 2)
주의 사항
match() vs search() vs findall()
print(re.match(r'\d','abc1')) # None
print(re.search(r'\d','abc1').group()) # 1
print(re.findall(r'\d','abc1')) # ['1']
탐욕적 vs 비탐욕적 매칭
print(re.findall(r'a\d+?','a123')) # ['a1']
print(re.findall(r'a\d+','a123')) # ['a123']
플래그 사용 시 주의
# flags 매개변수 명시 필요
print(re.split('a','1A1a2', flags=re.IGNORECASE))
실용적 예제
# 전화번호 매칭
print(re.findall(r'\d{3}-\d{4}-\d{4}', '010-1234-5678'))
# IP 주소 검증
ip_pattern = r"((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)"
print(re.search(ip_pattern, "192.168.0.1"))