본문 바로가기

Python

7-9. 정규 표현식(Regular Expression)으로 문자열 다루기

파이썬 정규 표현식으로 문자열 다루기

안녕하세요! 지난 시간에는 파이썬에서 날짜와 시간을 다루는 데 필수적인 datetime 모듈에 대해 알아보았습니다. 이제 시간 관련 데이터를 정확하고 유연하게 처리할 수 있게 되셨을 거예요!

이번 시간에는 파이썬에서 **정규 표현식(Regular Expression)**을 사용하여 문자열을 검색하고 조작하는 방법에 대해 알아보겠습니다. 정규 표현식은 특정 패턴을 가진 문자열을 찾거나, 추출하거나, 바꾸는 데 사용되는 강력한 도구입니다.

일반적인 문자열 메서드(find(), replace(), split())로는 처리하기 어려운 복잡한 문자열 패턴을 다룰 때 정규 표현식이 빛을 발합니다. 마치 특정 규칙을 가진 문자열을 찾아내는 '패턴 탐정'과 같다고 생각하시면 됩니다.


Part 1: 정규 표현식(Regular Expression)이란 무엇인가?

정규 표현식(Regular Expression), 줄여서 정규식(Regex) 또는 RegExp는 문자열에서 특정 패턴을 검색, 추출, 또는 대체하는 데 사용되는 문자열입니다. 특정한 규칙을 가진 문자의 조합으로 이루어지며, 이 규칙을 통해 복잡한 문자열 패턴을 정의할 수 있습니다.

1. 정규 표현식의 필요성

  • 복잡한 패턴 검색: "이메일 주소 형식 찾기", "전화번호 형식 찾기", "HTML 태그 제거" 등 고정된 문자열이 아닌, 특정 규칙을 가진 문자열을 찾을 때 유용합니다.
  • 데이터 유효성 검사: 사용자 입력이 특정 형식(예: 비밀번호 규칙, 날짜 형식)을 따르는지 검사할 때 사용합니다.
  • 문자열 조작: 특정 패턴에 맞는 부분을 한 번에 바꾸거나, 분리할 때 사용합니다.

2. 파이썬의 re 모듈

파이썬에서는 re 모듈을 통해 정규 표현식을 지원합니다.

Python
 
import re

Part 2: 정규 표현식의 기본 패턴

정규 표현식은 다양한 메타 문자(Meta Characters)와 시퀀스를 사용하여 패턴을 정의합니다.

메타 문자/시퀀스 설명 예시 (패턴) 매칭되는 문자열
. 모든 단일 문자 (줄바꿈 문자 \n 제외) a.b acb, aab
^ 문자열의 시작 ^Hello Hello World
$ 문자열의 끝 World$ Hello World
* 앞의 문자가 0번 이상 반복 ab*c ac, abc, abbbc
+ 앞의 문자가 1번 이상 반복 ab+c abc, abbbc
? 앞의 문자가 0번 또는 1번 반복 ab?c ac, abc
{m} 앞의 문자가 m번 반복 a{3}b aaab
{m,n} 앞의 문자가 m번 이상 n번 이하 반복 a{2,4}b aab, aaab, aaaab
[] 괄호 안의 문자 중 하나 (문자 클래스) [abc] a, b, c
[^] 괄호 안의 문자를 제외한 모든 문자 [^abc] d, e, 1
` ` OR 조건 (둘 중 하나) `a
() 그룹화 (패턴 묶기, 캡처) (ab)+ ab, abab
\ 특수 문자를 일반 문자로, 일반 문자를 특수 문자로 (이스케이프) \. . (점 문자)
\d 모든 숫자 (0-9) \d+ 123, 45
\D 숫자가 아닌 모든 문자 \D+ abc, !@#
\w 모든 단어 문자 (알파벳, 숫자, 밑줄 _) \w+ hello_123
\W 단어 문자가 아닌 모든 문자 \W+ !@#,
\s 모든 공백 문자 (스페이스, 탭, 줄바꿈 등) \s+ , \n
\S 공백 문자가 아닌 모든 문자 \S+ abc, 123
\b 단어 경계 (단어의 시작이나 끝) \bcat\b cat in "The cat sat"
\B 단어 경계가 아님 \Bcat\B cat in "wildcat"
Sheets로 내보내기

Part 3: re 모듈의 주요 함수

re 모듈은 정규 표현식을 사용하여 문자열을 처리하는 다양한 함수를 제공합니다.

1. re.match(pattern, string) - 문자열 시작부터 매칭 확인

  • 문자열의 시작 부분부터 패턴과 일치하는지 확인합니다.
  • 일치하면 Match object를 반환하고, 일치하지 않으면 None을 반환합니다.

예시:

Python
 
# 파일 이름: re_match.py
import re

text1 = "Hello World"
text2 = "World Hello"

# 'Hello'로 시작하는지 매칭
match_obj1 = re.match("Hello", text1)
match_obj2 = re.match("Hello", text2)

if match_obj1:
    print(f"'{text1}'에서 매칭 성공: {match_obj1.group()}") # 매칭된 문자열 반환
else:
    print(f"'{text1}'에서 매칭 실패")

if match_obj2:
    print(f"'{text2}'에서 매칭 성공: {match_obj2.group()}")
else:
    print(f"'{text2}'에서 매칭 실패")

# 숫자 패턴 매칭
match_obj3 = re.match(r"\d+", "123abc") # r""는 Raw String (이스케이프 문자 처리 용이)
if match_obj3:
    print(f"숫자 매칭 성공: {match_obj3.group()}")

match_obj4 = re.match(r"\d+", "abc123")
if match_obj4:
    print(f"숫자 매칭 성공: {match_obj4.group()}")
else:
    print(f"숫자 매칭 실패: 문자열 시작에 숫자가 없음")

 

[VS Code 터미널 출력]

파이썬 re.match 함수 사용 예시

2. re.search(pattern, string) - 문자열 전체에서 첫 번째 매칭 확인

  • 문자열 전체에서 패턴과 일치하는 첫 번째 부분을 찾습니다.
  • 일치하면 Match object를 반환하고, 일치하지 않으면 None을 반환합니다. (re.match와 달리 시작 위치에 상관없이 찾습니다.)

예시:

Python
 
# 파일 이름: re_search.py
import re

text = "My phone number is 010-1234-5678. Call me!"

# 전화번호 패턴 검색 (첫 번째만 찾음)
# \d{3} : 숫자 3개
# - : 하이픈
# \d{4} : 숫자 4개
phone_pattern = r"\d{3}-\d{4}-\d{4}"
search_obj = re.search(phone_pattern, text)

if search_obj:
    print(f"전화번호 매칭 성공: {search_obj.group()}")
    print(f"시작 인덱스: {search_obj.start()}")
    print(f"끝 인덱스: {search_obj.end()}")
    print(f"매칭 범위: {search_obj.span()}")
else:
    print("전화번호 매칭 실패")

# 이메일 패턴 검색
email_text = "Contact me at user@example.com or admin@domain.org"
email_pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
search_email = re.search(email_pattern, email_text)

if search_email:
    print(f"이메일 매칭 성공: {search_email.group()}")
else:
    print("이메일 매칭 실패")

 

[VS Code 터미널 출력]

파이썬 re.search 함수 사용 예시

3. re.findall(pattern, string) - 모든 매칭 결과 리스트로 반환

  • 문자열 전체에서 패턴과 일치하는 모든 부분을 찾아 리스트로 반환합니다.

예시:

Python
 
# 파일 이름: re_findall.py
import re

text = "Numbers: 123, 45, 6789. Also 0 and 100."

# 모든 숫자 찾기
numbers_found = re.findall(r"\d+", text)
print(f"찾은 모든 숫자: {numbers_found}")

# 모든 단어 찾기 (알파벳만)
words_found = re.findall(r"[a-zA-Z]+", text)
print(f"찾은 모든 단어: {words_found}")

# 이메일 주소 모두 찾기
email_text = "user1@example.com, user2@domain.org, invalid-email, user3@test.net"
email_pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
all_emails = re.findall(email_pattern, email_text)
print(f"찾은 모든 이메일: {all_emails}")

 

[VS Code 터미널 출력]

파이썬 re.findall 함수 사용 예시

4. re.sub(pattern, repl, string) - 매칭되는 부분 대체

  • 문자열에서 패턴과 일치하는 모든 부분을 repl (대체 문자열)로 바꿉니다.

예시:

Python
 
# 파일 이름: re_sub.py
import re

text = "Today is 2024-07-05. Tomorrow is 2024-07-06."

# 날짜 형식을 'YYYY/MM/DD'로 변경
# (\d{4}) : 4자리 숫자를 그룹 1로 캡처
# (\d{2}) : 2자리 숫자를 그룹 2로 캡처
# (\d{2}) : 2자리 숫자를 그룹 3으로 캡처
# \g<1>, \g<2>, \g<3> : 캡처된 그룹 참조
date_pattern = r"(\d{4})-(\d{2})-(\d{2})"
replaced_text = re.sub(date_pattern, r"\g<1>/\g<2>/\g<3>", text)
print(f"날짜 형식 변경: {replaced_text}")

# 모든 숫자 제거
no_numbers_text = re.sub(r"\d+", "", text)
print(f"숫자 제거: {no_numbers_text}")

# 공백을 하이픈으로 대체
spaced_text = "This is a test string with spaces."
hyphenated_text = re.sub(r"\s+", "-", spaced_text)
print(f"공백을 하이픈으로: {hyphenated_text}")

 

[VS Code 터미널 출력]

파이썬 re.sub 함수 사용 예시

Part 4: 정규 표현식 컴파일 (re.compile)

동일한 정규 표현식 패턴을 여러 번 사용해야 할 경우, re.compile() 함수를 사용하여 패턴을 미리 컴파일(pre-compile)할 수 있습니다. 이렇게 하면 매번 패턴을 파싱하는 오버헤드를 줄여 성능을 향상시킬 수 있습니다.

예시:

Python
 
# 파일 이름: re_compile.py
import re
import time

# 컴파일하지 않은 패턴 사용
start_time = time.time()
for _ in range(100000):
    re.search(r"\d{3}-\d{4}-\d{4}", "My phone is 010-1234-5678.")
end_time = time.time()
print(f"컴파일하지 않은 패턴 소요 시간: {end_time - start_time:.4f}초")

# 패턴 컴파일
phone_pattern_compiled = re.compile(r"\d{3}-\d{4}-\d{4}")

# 컴파일된 패턴 사용
start_time = time.time()
for _ in range(100000):
    phone_pattern_compiled.search("My phone is 010-1234-5678.")
end_time = time.time()
print(f"컴파일된 패턴 소요 시간: {end_time - start_time:.4f}초")
  • 반복 횟수가 많을수록 컴파일된 패턴의 성능 이점이 더 명확해집니다.

 

[VS Code 터미널 출력]

파이썬 re.compile 함수 사용 예시

(소요 시간은 시스템 환경에 따라 다를 수 있습니다.)


마무리하며

이번 시간에는 파이썬에서 정규 표현식(Regular Expression)을 사용하여 문자열을 검색하고 조작하는 방법에 대해 자세히 알아보았습니다.

  • 정규 표현식: 특정 패턴을 가진 문자열을 정의하고 찾기 위한 강력한 도구.
  • re 모듈: 파이썬에서 정규 표현식을 다루는 표준 모듈.
  • 주요 함수:
    • re.match(): 문자열 시작부터 매칭.
    • re.search(): 문자열 전체에서 첫 번째 매칭.
    • re.findall(): 모든 매칭 결과를 리스트로.
    • re.sub(): 매칭되는 부분을 대체.
  • re.compile(): 동일한 패턴을 여러 번 사용할 때 성능 최적화를 위해 패턴을 미리 컴파일.

정규 표현식은 처음에는 다소 복잡하고 어렵게 느껴질 수 있지만, 문자열 처리의 강력한 유연성을 제공하므로 꾸준히 연습하여 익숙해지는 것이 중요합니다. 웹 크롤링, 데이터 파싱, 로그 분석 등 다양한 분야에서 매우 유용하게 활용될 것입니다.

이것으로 '파이썬 고급 문법 & 실전 예제' 챕터의 여섯 번째 포스팅이 마무리됩니다. 다음 포스팅에서는 파이썬에서 데이터를 직렬화하고 역직렬화하는 데 사용되는 JSON과 Pickle 모듈에 대해 알아보겠습니다.


궁금한 점이 있다면 언제든지 질문해주세요! 다음 포스팅에서 만나요!

반응형