아래 예제는 정규 표현식(Regular Expression)을 이용해 전화번호 패턴을 찾아내는 프로그램이다.
>>> import re
>>> phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
>>> mo = phoneNumRegex.search('My number is 415-555-4242.')
>>> print('Phone number found: ' + mo.group())
Phone number found: 415-555-4242
예제 출처: Automate the Boring Stuff with Python (https://automatetheboringstuff.com/2e/chapter7/)
위 코드를 한 줄씩 살펴보자.
import re
파이썬 내장 모듈인 re(정규 표현식, Regular Expression)을 가져온다.
정규 표현식은 문자열 검색, 패턴 매칭, 대체 등을 쉽게 할 수 있도록 도와준다. 복잡한 문자열 처리를 간단하게 해결할 수 있다.
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
re.compile() 함수를 사용하여 전화번호 형식에 맞는 정규 표현식을 컴파일한다.
* /d: 숫자(0-9) 의미
* (r' ') : 원시 문자열(raw string)의 의미. 앞에 r을 붙여 원시문자열로 만들어서 백슬래시를 이스케이프 문자로 처리하지 않도록 한다.
정규 표현식의 컴파일
- 정규 표현식 문자열(r'\d\d\d-\d\d\d\d-\d\d\d\d')을 해석하여 패턴 객체(phoneNumRegex)로 만들어 재사용 가능하게 준비하는 과정. 이 패턴 객체는 이후에 문자열을 검색하거나 매칭할 때 사용된다.
- 컴파일을 하지 않으면 매번 패턴을 직접 사용해야 한다. 이 경우 Python이 매번 새로운 패턴을 해석해야 한다.
mo1 = re.search(r'\d\d\d-\d\d\d-\d\d\d\d', 'My number is 415-777-5353.')
mo2 = re.search(r'\d\d\d-\d\d\d-\d\d\d\d', 'My number is 415-999-8181.') - 정규 표현식을 한 번만 컴파일하면, 패턴 객체(phoneNumRegex)를 계속 재사용할 수 있다. 반복적인 작업에서는 컴파일된 패턴을 사용하는 것이 더 효율적이다.
방식 | 사용법 | 장점 | 사용 사례 |
패턴 객체 방식 | pattern = re.compile(r'패턴') pattern.search('문자열') |
- 패턴을 미리 컴파일하여 성능 최적화 가능 - 반복 작업에 효율적 |
- 동일한 패턴을 반복 사용 시 - 대량의 데이터에서 검색할 때 |
직접 사용 방식 | re.search(r'패턴', '문자열') | - 코드가 간결 - 한 번만 사용할 때 유용 |
- 간단한 문자열 검색 시 - 임시적인 패턴 사용 시 |
mo = phoneNumRegex.search('My number is 415-555-4242.')
- 생성된 패턴 객체(phoneNumRegex)에서 .search() 메서드를 호출하여 패턴 객체의 문자열을 검색한다.
- .search() 메서드는 문자열 전체를 검색하며, 첫 번째로 매칭되는 부분만 매치 객체(Match Object)로 반환한다.
- 여기서는 415-555-4242 부분이 정규 표현식과 일치하므로, 이 결과가 매치 객체로 반환된다.
- 이 매치 객체는 mo 변수에 저장된다.
- 만약 매칭되는 부분이 없다면, mo에는 None이 저장된다.
print('Phone number found: ' + mo.group())
매칭된 전화번호를 출력한다.
mo는 Match 객체이므로, .group() 메서드를 사용하여 매칭된 문자열을 가져올 수 있다.
mo.group()은 415-555-4242를 반환한다.
.gorup()메서드를 사용하는 이유
이런 질문이 생겼다. 이미 .search() 메서드를 호출해서 매칭 객체를 반환해서 mo 변수에 저장을 했는데, 왜 굳이 다시 .group() 메서드를 호출히야 하지??
내 질문에 대해 챗 지피티가 다음과 같이 설명을 해 주었다.
결론부터 말하면, mo 자체만으로는 매칭된 문자열을 직접 출력할 수 없고, .groupe() 메서드를 사용해야만 매칭된 실제 문자열을 얻을 수 있다는 것이다.
1. mo는 매칭 객체(re.Match 객체)
import re
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('My number is 415-555-4242.')
print(mo)
# 출력: <re.Match object; span=(13, 25), match='415-555-4242'>
mo는 <re.Match object>라는 매칭 객체이다.
이 객체 자체를 출력하면 객체 정보(span, match 등)을 보여주지만, 우리가 원하는 순수한 매칭된 문자열을 직접 반환하지는 않는다.
2. .group() 메서드를 사용해야 실제 매칭된 문자열을 얻을 수 있음
print(mo.group())
# 출력: 415-555-4242
.group() 메서드를 사용하면 매칭된 문자열을 반환한다.
이 메서드는 패턴 전체와 일치하는 문자열을 반환하며, 만약 그룹화(()를 사용)했다면 .group(1), .group(2)처럼 세부 그룹도 추출할 수 있다.
세부 그룹 추출이란, 정규 표현식에서 괄호(())를 사용하여 패턴의 일부를 그룹화하고, 그 특정 부분만 따로 추출할 수 있도록 하는 기능을 말한다. 즉, 하나의 정규 표현식으로 전체 매칭 결과뿐만 아니라,
그 안에 포함된 세부적인 값들을 따로따로 가져올 수 있다.
예시: 전화번호에서 지역번호, 중간번호, 뒷번호를 각각 추출하기
import re
# 그룹화된 정규 표현식
phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')
# 문자열에서 패턴 검색
mo = phoneNumRegex.search('My number is 415-555-4242.')
# 전체 매칭된 문자열
print(mo.group()) # 출력: 415-555-4242
# 세부 그룹별 추출
print(mo.group(1)) # 출력: 415 (지역번호)
print(mo.group(2)) # 출력: 555 (중간번호)
print(mo.group(3)) # 출력: 4242 (뒷번호)
'AI Journey > 혼자 공부하는 파이썬' 카테고리의 다른 글
[파이썬] 리스트 - 리스트 내용을 삭제하는 메서드 .remove(), .pop(), clear() 비교 (0) | 2025.02.21 |
---|---|
[파이썬] 정규 표현식(Regex) 2. 그룹화(Grouping) (예제: 전화번호 찾기) (0) | 2025.02.20 |
[파이썬] pass 문을 자리표시자(placeholder)로 사용하기 (0) | 2025.02.16 |
[파이썬] 함수 - 기본 매개변수 값 (Default Parameter Value) (0) | 2025.02.16 |
[파이썬] 문자열 조작 - strip() 메소드 예시 뜯어보기 (0) | 2025.02.14 |