Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬(Python) 정규 표현식(Regex)으로 패턴 매칭하기: 기본 개념부터 실전 활용까지

정규 표현식(Regular Expression)이란?

실제 개발 환경에서 대부분의 프로그래밍 언어는 문자열 파싱을 정규 표현식(Regular Expression, 줄여서 Regex)으로 처리합니다. 파이썬에서 정규 표현식은 특정 텍스트 패턴을 검색하고 일치시키기 위해 사용하는 강력한 방법입니다.

파이썬에는 기본적으로 re 모듈이 내장되어 있어 별도의 설치 없이 정규 표현식 기능을 바로 사용할 수 있습니다.

파이썬에서 정규 표현식 검색은 일반적으로 다음과 같이 작성합니다.

match = re.search(pattern, string)

re.search() 메서드는 정규 표현식 패턴과 문자열 두 개의 인자를 받아, 해당 문자열 안에서 패턴을 검색합니다. 패턴이 발견되면 match 객체를 반환하고, 발견되지 않으면 None을 반환합니다. 즉, 주어진 문자열이 특정 패턴과 일치하는지 확인하고, 필요하다면 관련 정보를 담은 부분 문자열(substring)까지 추출할 수 있습니다.

정규 표현식은 다음과 같은 질문에 답하는 데 활용될 수 있습니다.

  • 이 문자열은 유효한 URL인가?
  • /etc/passwd 파일에서 특정 그룹에 속한 사용자는 누구인가?
  • 로그 파일에 기록된 모든 경고 메시지의 날짜와 시간은 언제인가?
  • 방문자가 입력한 URL에서 요청된 사용자명과 문서는 무엇인가?

패턴 매칭의 기본

정규 표현식은 하나의 작은 언어라고 할 수 있을 만큼 다양한 문법을 가지고 있습니다. 특수 문자를 활용해 알 수 없는 문자열을 매칭할 수도 있지만, 먼저 알파벳, 숫자, 공백처럼 항상 자기 자신과 일치하는 리터럴(literal) 문자부터 시작해 보겠습니다.

다음은 가장 기본적인 예제입니다.

# 정규 표현식을 위해 're' 모듈 임포트
import re
#
search_string = "TutorialsPoint"
pattern = "Tutorials"
match = re.match(pattern, search_string)
# search() 이후 if문으로 성공 여부 확인
if match:
    print("regex matches: ", match.group())
else:
    print('pattern not found')

실행 결과

regex matches: Tutorials

문자열 매칭하기

파이썬의 re 모듈에는 다양한 메서드가 포함되어 있으며, 특정 정규 표현식이 주어진 문자열과 일치하는지 확인하려면 re.search()를 사용하면 됩니다. 반환되는 re.MatchObject는 매칭이 문자열의 어느 부분에서 발견되었는지 등 추가 정보도 제공합니다.

문법

matchObject = re.search(pattern, input_string, flags=0)

예제

# 정규 표현식을 위해 're' 모듈 임포트
import re
# 날짜 형식의 문자열을 매칭하는 정규 표현식
regex = r"([a-zA-Z]+) (\d+)"
if re.search(regex, "Jan 2"):
    match = re.search(regex, "Jan 2")
    # 문자열 시작부터 끝까지 매칭되므로 [0, 5) 출력
    print("Match at index %s, %s" % (match.start(), match.end()))
    # 그룹(group)에는 매칭된 값들이 저장됩니다.
    # match.group(0): 매칭된 전체 문자열 반환
    # match.group(1), match.group(2), ... : 입력 문자열에서
    # 왼쪽부터 오른쪽 순서로 캡처 그룹 반환
    # match.group()은 match.group(0)과 동일
    print("Full match: %s" % (match.group(0)))  # "Jan 2" 출력
    print("Month: %s" % (match.group(1)))  # "Jan" 출력
    print("Day: %s" % (match.group(2)))  # "2" 출력
else:
    # re.search()가 매칭에 실패하면 None 반환
    print("Pattern not Found! ")

실행 결과

Match at index 0, 5
Full match: Jan 2
Month: Jan
Day: 2

re.search()는 첫 번째 매칭을 찾으면 검색을 중단하기 때문에, 데이터 추출보다는 정규 표현식의 일치 여부를 테스트하는 용도에 더 적합합니다.

캡처 그룹(Capturing Groups)

패턴에 괄호가 두 개 이상 포함되어 있다면, 괄호() 그룹 메커니즘과 findall()을 활용해 결과를 문자열 리스트가 아닌 튜플(tuple) 형태로 받을 수 있습니다. 매칭된 각 패턴은 하나의 튜플로 표현되며, 각 튜플은 group(1), group(2)... 데이터를 담고 있습니다.

import re
regex = r'([\w\.-]+)@([\w\.-]+)'
str = ('hello john@hotmail.com, hello@Tutorialspoint.com, hello python@gmail.com')
matches = re.findall(regex, str)
print(matches)
for tuple in matches:
    print("Username: ", tuple[0]) # 사용자명
    print("Host: ", tuple[1]) # 호스트

실행 결과

[('john', 'hotmail.com'), ('hello', 'Tutorialspoint.com'), ('python', 'gmail.com')]
Username: john
Host: hotmail.com
Username: hello
Host: Tutorialspoint.com
Username: python
Host: gmail.com

문자열 찾아 바꾸기(Find & Replace)

정규 표현식의 또 다른 대표적인 활용 사례는 주어진 문자열에서 패턴에 해당하는 모든 부분을 찾아 다른 값으로 교체하는 것입니다. re.sub(pattern, replacement, string) 함수가 바로 이 역할을 수행합니다. 예를 들어, 기존 이메일 도메인을 새 도메인으로 일괄 변경하는 경우를 살펴보겠습니다.

코드

# 필요한 라이브러리
import re
# 주어진 문자열
str = ('hello john@hotmail.com, hello@Tutorialspoint.com, hello python@gmail.com, Hello World!')
# 매칭할 패턴
pattern = r'([\w\.-]+)@([\w\.-]+)'
# 매칭된 패턴을 아래 값으로 교체
replace = r'\1@XYZ.com'
    ## re.sub(pat, replacement, str) -- 모든 교체가 반영된 새 문자열 반환
    ## \1은 group(1), \2는 group(2)를 의미
print(re.sub(pattern, replace, str))

실행 결과

hello john@XYZ.com, hello@XYZ.com, hello python@XYZ.com, Hello World!

re 모듈 옵션 플래그(Flags)

파이썬 정규 표현식에서는 다양한 옵션 플래그를 사용해 패턴 매칭의 동작 방식을 조정할 수 있습니다. 이 선택적 인자는 search(), findall() 등의 함수에 추가로 전달하며, 예를 들어 re.search(pattern, string, re.IGNORECASE)처럼 사용합니다.

  • IGNORECASE
    이름 그대로 패턴 매칭 시 대소문자를 구분하지 않습니다. 이 플래그를 사용하면 'a'와 'A'를 동일하게 취급하여 둘 다 매칭됩니다.
  • DOTALL
    re.DOTALL 플래그를 사용하면 점(.) 메타 문자가 줄바꿈 문자(\n)를 포함한 모든 문자와 매칭됩니다.
  • MULTILINE
    re.MULTILINE 플래그를 사용하면 문자열의 각 줄마다 시작(^)과 끝($)을 매칭할 수 있습니다. 일반적으로 ^와 $는 문자열 전체의 시작과 끝에만 매칭되지만, 이 플래그를 적용하면 여러 줄로 구성된 문자열에서도 줄 단위 매칭이 가능합니다.