본 글은 '점프 투 파이썬(박응용)'을 바탕으로 공부한 내용을 정리한 글입니다.
정규 표현식(regular expression): 문자열의 패턴을 표현하는 특별한 문법
정규 표현식의 기초, 메타 문자
메타 문자: 문자의 본래 의미가 아니라 특별한 의미를 가진 문자
- 정규 표현식에 사용하면 특별한 의미를 갖게 되는 메타 문자들
# . ^ $ * + ? { } [ ] \\ | ( )
[ ] 문자 - 문자 클래스
- 문자 클래스: 이 중에서 아무거나 하나라는 의미
- e.g.
[abc]: a, b, c 중 하나 a: 매치됨before: 매치됨done: 매치되지 않음
- e.g.
- 범위 지정하기 -
-(하이픈) 사용법[a-z]: 모든 소문자 알파벳[a-zA-Z]: 모든 알파벳(대, 소문자 모두)[0-9]: 모든 숫자(0부터 9까지)[가-힣]: 모든 한글(가부터 힣까지)
- 제외하기 -
^사용법[^0-9]: 숫자가 아닌 모든 문자(알파벳, 특수 문자, 공백 등)[^A-Z]: 대문자가 아닌 모든 문자
- 자주 사용하는 문자 클래스
\d==[0-9]\D==[^0-9]\s==[ \t\n\r\f\v](whitespace 문자와 매치)\S==[^ \t\n\r\f\v]\w==[a-zA-Z0-9](문자 + 숫자; alphanumeric)\W==[^a-zA-Z0-9](문자 + 숫자가 아닌 문자)
.(dot) 문자 - \n을 제외한 모든 문자
- .:
\n을 제외한 모든 문자와 매치됨- e.g.
a.b: a, b 사이 어떤 문자 들어가도 매치 aab: 매치됨a0b: 매치됨abc: 매치되지 않음
- e.g.
- 주의:
[.]의 .은 메타 문자가 아니라, ‘.’ 문자 그대로- e.g.
a[.]b: 문자열a.b와만 매치됨 a.b: 매치됨a0b: 매치되지 않음
- e.g.
*문자
*앞에 있는 문자가 0부터 (이론상) 무한대까지 반복될 수 있음- e.g.
ca*t: a가 0부터 무한대까지 반복될 수 있음 ct: 매치됨(a가 0번 반복)cat: 매치됨(a가 1번 반복)caaat: 매치됨(a가 3번 반복)
- e.g.
+문자
+: 앞에 있는 문자가 1부터 무한대까지 반복될 수 있음- e.g.
ca+t: a가 1번 이상 반복될 수 있음 ct: 매치되지 않음(a가 0번 반복)cat: 매치됨(a가 1번 반복)caaat: 매치됨(a가 3번 반복)
- e.g.
{ }문자와 ?문자
{ }문자: 반복 횟수 지정- e.g.
ca{2}t: a를 2번 반복cat: 매치되지 않음(a가 1번 반복)caat: 매치됨(a가 2번 반복)caaat: 매치되지 않음(a가 3번 반복)
- e.g.
ca{2,4}t: a를 2~4회 반복cat: 매치되지 않음(a가 1번 반복)caat: 매치됨(a가 2번 반복)caaat: 매치됨(a가 3번 반복)
- e.g.
?=={0,1}(있어도 되고 없어도 됨)- e.g.
ab?c: b가 있어도 되고 없어도 됨abc: 매치됨(b가 1번 반복)ac: 매치됨(b가 0번 반복)
- e.g.
파이썬에서 정규 표현식을 지원하는 re 모듈
re 모듈: 표준 라이브러리
패턴: 정규식을 컴파일한 결과
import re
p = re.compile('ab*') # 정규 표현식 컴파일
정규식을 이용한 문자열 검색
컴파일된 패턴 객체가 제공하는 메서드
Method 목적
| match() | 문자열의 처음부터 정규식과 매치되는지 조사, match 객체/None으로 반환 |
|---|---|
| search() | 문자열 전체 검색해 정규식과 매치되는지 조사, match 객체/None으로 반환 |
| findall() | 정규식과 매치되는 모든 substring을 리스트로 반환 |
| finditer() | 정규식과 매치되는 모든 substring을 iterator로 반환 |
match
match(): 문자열의 처음부터 정규식과 매치되는지 조사
import re
p = re.compile('[a-z]+') # 알파벳 소문자가 1번 이상 반복
m = p.match("python")
print(m) # <re.Match object; span=(0, 6), match='python'>
m = p.match("3 python")
# 처음 나오는 3이 정규 표현식에 부합되지 않으므로
print(m) # None
search
search(): 문자열 전체를 검색해 정규식과 매치되는지 조사
import re
p = re.compile('[a-z]+') # 알파벳 소문자가 1번 이상 반복
m = p.search("python")
print(m) # <re.Match object; span=(0, 6), match='python'>
m = p.search("3 python")
# 3 이후의 python 문자열과 매치됨
print(m) # <re.Match object; span=(2, 8), match='python'>
findall
findall(): 정규식과 매치되는 모든 substring을 list로 반환
import re
p = re.compile('[a-z]+')
result = p.findall('life is too short')
print(result) # ['life', 'is', 'too', 'short']
finditer
finditer(): 정규식과 매치되는 모든 substring을 iterator로 반환
- iterator 객체가 포함하는 각 요소는 match 객체
import re
p = re.compile('[a-z]+')
result = p.finditer('life is too short')
print(result) # <callable_iterator object at ...>
for r in result: print(r)
"""
<re.Match object; span=(0, 4), match='life'>
<re.Match object; span=(5, 7), match='is'>
<re.Match object; span=(8, 11), match='too'>
<re.Match object; span=(12, 17), match='short'>
"""
match 객체의 메서드
Method 목적
| group() | 매치된 문자열 리턴 |
|---|---|
| start() | 매치된 문자열의 시작 위치 리턴 |
| end() | 매치된 문자열의 끝 위치 리턴 |
| span() | 매치된 문자열의 (시작, 끝)에 해당하는 튜플 리턴 |
import re
p = re.compile('[a-z]+')
m = p.match("python")
print(m.group()) # python
print(m.start()) # 0
print(m.end()) # 6
print(m.span()) # (0, 6)
m = p.search("3 python")
print(m.group()) # python
print(m.start()) # 2
print(m.end()) # 8
print(m.span()) # (2, 8)
컴파일 옵션
DOTALL(S)
.: 줄바꿈 문자 \n를 제외한 모든 문자와 매치됨 → \n 포함하고 싶은 경우 re.DOTALL 또는 re.S 옵션 사용해 컴파일
- 여러 줄로 이루어진 문자열에서 줄바꿈 문자에 상관없이 검색 시 사용
import re
p = re.compile('a.b', re.DOTALL)
# 또는 p = re.compile('a.b', re.S)
m = p.match('a\\nb')
print(m) # <re.Match object; span=(0, 3), match='a\\nb'>
IGNORECASE(I)
re.IGNORECASE 또는 re.I : 대소문자 구별 없이 매치 수행
import re
p = re.compile('[a-z]+', re.I)
m = p.match('python')
print(m) # <re.Match object; span=(0, 6), match='python'>
m = p.match('PYTHON')
print(m) # <re.Match object; span=(0, 6), match='PYTHON'>
m = p.match('Python')
print(m) # <re.Match object; span=(0, 6), match='Python'>
MULTILINE(M)
re.multiline 또는 re.M: 메타 문자 ^(문자열의 처음), $(끝)을 문자열의 각 줄마다 적용
import re
# 백슬래시 인식 위해 \\\\ 사용
p = re.compile("^python\\\\s\\\\w+")
"""
python이라는 문자열로 시작
그 뒤에 whitespace
그 뒤에 alphanumeric
"""
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data)) # ['python one']
# ^ 에 의해 python이라는 문자열 사용한 첫 번째 줄만 매치
import re
p = re.compile("^python\\\\s\\\\w+", re.MULTILINE)
# ^ 메타 문자가 각 줄의 처음을 의미하게 됨
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data)) # ['python one', 'python two', 'python three']
VERBOSE(X)
re.VERBOSE 또는 re.X : 정규식을 주석 또는 줄 단위로 구분. 문자열에 사용된 주석, 화이트스페이스는 컴파일 시 제거됨
e.g. 이메일 주소 검증하는 정규식
import re
"""
re.VERBOSE 옵션을 사용하지 않은 경우
email_pattern = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$')
"""
# re.VERBOSE 옵션 사용
email_pattern = re.compile(r"""
^ # 문자열의 시작
[a-zA-Z0-9._%+-]+ # 사용자명: 영문자, 숫자, 특수문자
@ # @ 기호
[a-zA-Z0-9.-]+ # 도메인명: 영문자, 숫자, 점, 하이픈
\\. # 점(.)
[a-zA-Z]{2,} # 최상위 도메인: 영문자 2자 이상
$ # 문자열의 끝
""", re.VERBOSE)
역슬래시 문제
파이썬 문자열 리터럴 규칙: 문자열 내의 \\ == \ (백슬래시 그 자체)
문자열에 따라 \ 이 반복되는 경우 → raw string 표현법 사용
+) raw string은 정규 표현식 뿐만 아니라 모든 문자열에 대해 사용 가능함
import re
p = re.compile(r'\\\\section') # \\를 1개만 써도 \\ 자체로 인식
예제
import re
# 이메일 주소의 사용자 이름과 도메인 각각 추출해 튜플로 반환
email_pattern = re.compile(r'([a-zA-Z0-9.%_+-]+)@([a-zA-Z0-9.-]+\\.[a-zA-Z]{2,})')
text = "제 이메일 주소는 user123@example.com 이고, 비상 연락처는 admin@company.co.kr 입니다."
matches = email_pattern.findall(text)
print(matches)
# 문자열 치환하기
phone_pattern = r'010-\\d{4}-\\d{4}'
text = "고객님 전화번호는 010-1234-5678 이며, 다음 전화번호 010-9876-5432는 가족 번호입니다."
masked = re.sub(phone_pattern, '[전화번호 마스킹]', text)
print(masked)'점프 투 파이썬' 카테고리의 다른 글
| [점프 투 파이썬] 8장 - 정규표현식: 강력한 정규 표현식의 세계 (3) | 2025.08.28 |
|---|---|
| [점프 투 파이썬] 7장 - 파이썬 날아오르기: type annotation(타입 어노테이션) (2) | 2025.08.27 |
| [점프 투 파이썬] 7장 - 파이썬 날아오르기: 이터레이터와 제너레이터 (1) | 2025.08.27 |
| [점프 투 파이썬] 7장 - 파이썬 날아오르기: 클로저와 데코레이터 (0) | 2025.08.27 |
| [점프 투 파이썬] 7장 - 파이썬 날아오르기: 유니코드 (0) | 2025.08.27 |