본문 바로가기
AI Journey/혼자 공부하는 파이썬

[파이썬] 정규 표현식(Regex) 1. 컴파일, Match 객체 (예제: 전화번호 찾기)

by 보눔비스타 2025. 2. 20.

아래 예제는 정규 표현식(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 (뒷번호)