본 글은 '점프 투 파이썬(박응용)'을 바탕으로 공부한 내용을 정리한 글입니다.
문자열 소비가 없는 메타 문자
조건만 확인하는 메타 문자들
`|`
`A|B`: A 또는 B
import re
p = re.compile('Crow|Servo')
m = p.match('CrowHello')
print(m) # <re.Match object; span=(0, 4), match='Crow'>
`^`
`^`: 문자열의 맨 처음과 일치
- `re.MULTILINE` 옵션 사용 시 문자열의 각 줄의 처음과 매치
import re
print(re.search('^Life', 'Life is too short')) # <re.Match object; span=(0, 4), match='Life'>
print(re.search('^Life', 'My Life')) # None
`$`
`$`: 문자열의 끝과 매치
- `re.MULTILINE` 옵션 사용 시 문자열의 각 줄의 끝과 매치
import re
print(re.search('Life$', 'Life is too short')) # None
print(re.search('Life$', 'My Life')) # <re.Match object; span=(3, 7), match='Life'>
`\A`
`\A`: 문자열의 맨 처음과 일치
- `re.MULTILINE` 옵션과 관계 없이 전체 문자열의 처음과 매치
`\Z`
`\Z`: 문자열의 끝과 매치
- `re.MULTILINE` 옵션과 관계 없이 전체 문자열의 끝과 ****매치
`\b`
`\b`: 화이트 스페이스로 구분되는 단어와 매치
import re
p = re.compile(r'\\bclass\\b')
"""
정규식 앞, 뒤가 화이트 스페이스로 구분된
class라는 단어와 매치됨
"""
print(p.search('no class at all')) # re.Match object; span=(3, 8), match='class'>
print(p.search('one subclass is')) # None(class 앞에 sub)
`\B`
`\B`: 화이트 스페이스로 구분된 단어가 아닌 경우에 매치
import re
p = re.compile(r'\\Bclass\\B')
print(p.search('no class at all')) # None
print(p.search('one subclass is')) # NOne
print(p.search('subclassis')) # <re.Match object; span=(3, 8), match='class'>
grouping
grouping의 목적
1. 여러 문자를 하나로 묶어 반복 처리
import re
text = "GoGoGo, HiHi, HelloHello, GoHi, hihi"
p = re.compile('(Go)+')
m = p.search(text)
print(m) # <re.Match object; span=(0, 6), match='GoGoGo'>
# group(): 매치된 문자열 리턴
print(m.group()) # GoGoGo
2. 매치된 문자열에서 원하는 부분만 추출
import re
p = re.compile(r'(.*?)')
# *: 더 이상 .에 해당하는 패턴이 나오지 않을 때까지 매치
# *?: 다음 패턴( ">)이 나타날 때까지만 최소한으로 매치
text = 'Google, Naver'
m = p.findall(text)
print(m) # [('<https://www.google.com>', 'Google'), ('<https://www.naver.com>', 'Naver')]
그루핑된 문자열 재참조하기
`\1, \2, \3...`: 정규식의 그룹 중 1, 2, 3…번째 그룹
# 두 단어가 반복되는 패턴 찾기
import re
# 그룹으로 묶어서 기억하고, \\1로 그 내용 다시 참조
p = re.compile(r'([a-zA-Z]+)\\1', re.IGNORECASE)
text = "GoGo, HiHi, HelloHello, GoHi, hihi"
matches = p.finditer(text)
full_matches = [m.group() for m in matches]
print(full_matches) # ['GoGo', 'HiHi', 'HelloHello', 'hihi']
# HTML 태그 쌍 찾기
import re
p = re.compile(r'<(.*?)>(.*?)</\\1>')
text = "<b>bold</b>는 글씨를 굵게 하고, <i>italic</i>은 글씨를 기울입니다."
matches = p.findall(text)
print(matches)
그루핑된 문자열에 이름 붙이기
`(?P<그룹명>...)` : 그룹에 이름 붙이기
import re
date = re.compile(r'(?P<year>\\d{4})-(?P<month>\\d{2})-(?P<day>\\d{2})')
text = "오늘의 날짜는 2025-08-28입니다. 내일의 날짜는 2025-08-29입니다."
matches_list = date.findall(text)
matches_iter = date.finditer(text)
print(matches_list) # [('2025', '08', '28'), ('2025', '08', '29')]
print([m.group('day') for m in matches_iter]) # ['28', '29']
재참조
import re
text = "이메일은 user1@google.google 이고, 다른 주소는 user2@naver.naver 입니다. user3@gmail.com은 제외합니다."
email_pattern = re.compile(r'[a-zA-Z0-9._%+-]+@(?P<domain>[a-zA-Z.-]+)\.(?P=domain)')
matches = email_pattern.finditer(text)
full_matches = [m.group() for m in matches]
print(full_matches) # ['user1@google.google', 'user2@naver.naver']
전방 탐색
전방 탐색
전방 탐색: 특정 조건이 있는지 확인, 그 부분은 결과에 포함 X
- 긍정형 전방 탐색 `(?=...)` : 뒤에 ...가 오는지 확인, 실제 결과에는 포함 X
- 부정형 전방 탐색 `(?!...)`: 뒤에 ...가 오지 않는지 확인, 실제 결과에는 포함 X
긍정형 전방 탐색 `(?=...)`
http:와 같이 콜론: 이 있는지는 확인하고 싶지만, 실제 결과는 http만 얻고 싶은 경우
import re
# .+: 어떤 문자든 1번 이상 반복
# (?=:): 뒤에 ':'이 오는지 확인, 결과에서는 제외
p = re.compile(".+(?=:)")
m = p.search("<http://google.com>")
print(m.group()) # http
뒤에 숫자가 있는 단어를 찾는 경우
import re
text = "apple pie, banana 1, kiwi 2, orange"
p = re.compile(r'\\w+(?=\\s+\\d+)')
m = p.findall(text)
print(m) # ['banana', 'kiwi']
부정형 전방 탐색 `(?!...)`
import re
# 파일 이름을 찾는 패턴: .*[.]*.*$
# .bat, .exe 파일은 제외하고 싶은 경우
# (?!bat$|exe$): 뒤에 bat 또는 exe가 오지 않는 경우
p = re.compile('.*[.](?!bat$|exe$).*$')
문자열 바꾸기
`re.sub()`: 정규식과 매치되는 부분을 다른 문자로 바꿈
re.sub(패턴, 바꿀_문자열, 대상_문자열)
count: 바꾸기 횟수 제어
import re
p = r'\\d'
text = '123456'
replaced = re.sub(p, '숫자', text, count=2)
print(replaced) # 숫자숫자3456
참조 구문 사용
이메일 주소에서 사용자 이름만 남기고 도메인 삭제하기
import re
text = "제 이메일은 이메일:user123@example.com입니다."
p = r'(이메일:\\s*)([a-zA-Z0-9.%_+-]+)@[a-zA-Z.-]+\\.[a-zA-Z]+'
replaced = re.sub(p, '\\\\g<1> \\\\g<2>', text)
print(replaced)
매개변수로 함수 넣기
람다 함수 사용해 모든 숫자를 두 배 하기
import re
text = "가격은 100원, 수량은 5개입니다."
p = r'\\d+'
doubled = re.sub(p, lambda x: str(int(x.group()) * 2), text)
print(doubled)
greedy 와 non-greedy
`*`: 최대한의 문자열 소비(greedy). 더 이상 해당하는 패턴이 없을 때까지 반복
`?`: 되도록 최소한 반복(non-greedy). 다음 패턴이 나올 때까지만 반복
import re
text = "(first)(second)(third)"
# greedy
p = r'\\(.*\\)'
m = re.findall(p, text)
print(m) # ['(first)(second)(third)'] # 마지막 ) 괄호까지 포함
# non-greedy
p = r'\\(.*?\\)'
m = re.findall(p, text)
print(m) # ['(first)', '(second)', '(third)'] # )가 나오면 다음으로 넘어감'점프 투 파이썬' 카테고리의 다른 글
| [점프 투 파이썬] 8장 - 정규표현식: 정규 표현식 시작하기 (0) | 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 |