Python(파이썬)_점프 투 파이썬/파이썬 날아오르기

파이썬 정규표현식

study note 2025. 9. 21. 03:13
반응형

❰정규표현식❱

-정규표현식에 대해 배워보자!

 

▶정규 표현식이란?

정규 표현식(Regular Expression, 이하 정규식)특정 규칙을 가진 문자열의 집합을 표현하는 방법입니다.
말이 조금 어려워 보일 수 있지만, 간단히 말하면 문자열에서 원하는 모양(패턴)을 찾기 위한 도구라고 생각하면 됩니다.

예를 들어, 우리가 평소에 “이 문장 안에서 숫자만 뽑아내자”라든지 “이 글에서 전화번호 형식인지 확인하자” 같은 일을 하고 싶을 때, 일일이 조건문과 반복문을 짜는 대신 정규식 하나만 작성하면 간단하게 해결할 수 있습니다.

정규는 특히 검색(Search), 추출(Extract), 치환(Replace) 작업에서 강력합니다.

검색: 웹 페이지에서 모든 이메일 주소 찾기
추출: 텍스트에서 ‘010-XXXX-XXXX’ 형태의 전화번호만 뽑아내기
치환: 특정 패턴을 찾아 다른 문자열로 바꾸기 (예: 공백 여러 개 → 하나의 공백)

 

즉, 정규는 복잡한 문자열 작업을 짧고 간결한 표현으로 처리할 수 있는 공식 같은 도구입니다.
그래서 웹 크롤링, 데이터 전처리, 로그 분석, 사용자 입력 검증 등 다양한 곳에서 널리 쓰입니다.

 

▶정규표현식이 왜 필요한가?

문자열 안에서 단순히 특정 단어를 찾는 정도라면 find() 같은 내장 함수를 써도 충분합니다.
하지만 실제 프로그래밍에서는 더 복잡한 상황이 자주 등장합니다. 이럴 때 정규 표현식을 쓰면 훨씬 쉽고 강력하게 문제를 해결할 수 있습니다.

 

예를 들면,

한 번에 'abc', 'acd'처럼 비슷하지만 조금씩 다른 문자열을 모두 찾아야 할 때.(다양한 패턴 검색)

이메일 주소가 올바른 형태인지, 전화번호가 규칙에 맞는지, 비밀번호가 조건을 만족하는지 검사할 때 (형식 검증(유효성 검사))

웹 페이지나 문서에서 특정 정보만 뽑아낼 때, 예를 들어 HTML에서 모든 URL 주소만 모으고 싶을 때.(데이터 추출)

수많은 파일이나 긴 텍스트 안에서 규칙에 맞는 부분을 찾아서 일괄적으로 수정할 때.(대량의 문자열 조작) 

이처럼 정규 표현식은 일일이 조건문을 작성하지 않고도 복잡한 문자열 문제를 짧고 명확한 한 줄의 표현식으로 처리할 수 있다는 점에서 매우 유용합니다.

 

▶정규 표현식의 기초, 메타문자 

정규식의 가장 중요한 개념은 메타문자(meta-characters)입니다. 메타문자는 그 자체의 의미가 아닌, 특별한 규칙을 나타내는 문자를 의미합니다.

 

이 메타문자들을 조합하면 매우 다양한 문자열 패턴을 정의할 수 있습니다.

아래는 각 메타 문자의 의미와 사용법에 대한 정리입니다.

 

[ ] 문자(문자클래스)

대괄호 안에 있는 문자 중 하나와 매치됩니다.(어떤 문자도 들어갈 수 있습니다.)

정규 표현식 문자열 매치 여부 및 설명
[abc] a "a"라는 문자열은 정규식과 일치하는 "a"가 있으므로 매치
before "before"라는 문자열은 "b"라는 맨앞의 문자가 정규식과 일치하므로 매치
dude "dude"는 [abc]중 어느 하나도 포함 되지 않으므로 정규식에 매치되지 않음.

위 표처럼 하나라도 일치하면 매칭가 가능 합니다.

만약 정규 표현식

[0-9]가 있으면 0부터 9까지의 숫자 하나와 매칭을 하게 됩니다

하이픈(-)은 부터를 의미하며 1부터5까지, A부터Z까지를 표현할 때 사용합니다.

아래는 간단한 예시 입니다.

 

문자 클래스
의 정규식
설명 예시
. 줄바꿈 문자(\n)를 제외한 모든 문자 1개 a.b는 'aab', 'acb', 'a3b' 등과 매치됩니다.
[ ] 대괄호 안의 문자 중 하나와 매치 [abc]는 'a', 'b', 'c' 중 하나와 매치됩니다.
[ - ] 범위 지정. 하이픈으로 범위를 지정할 수 있습니다. [0-9]는 모든 숫자, [a-z]는 모든 소문자와 매치됩니다.
[^ ] 괄호 안의 문자를 제외한 모든 문자와 매치 [^0-9]는 숫자를 제외한 모든 문자와 매치됩니다.
\d 모든 숫자와 매치됩니다. ([0-9]와 동일) \d+는 '123', '45', '7890' 등과 매치됩니다.
\D 숫자를 제외한 모든 문자와 매치됩니다. \D+는 'abc', 'hello', 'python' 등과 매치됩니다.
\w 알파벳, 숫자, 언더스코어(_)와 매치됩니다. \w+는 'word', 'var_1', 'Python3' 등과 매치됩니다.
\W 알파벳, 숫자, 언더스코어를 제외한 모든 문자와 매치됩니다. \W+는 !@#, ()-, (공백) 등과 매치됩니다.
\s 모든 공백 문자와 매치됩니다. (스페이스, 탭, 줄바꿈 등) \s+는 여러 개의 공백, 탭, 줄바꿈을 포함한 문자열과 매치됩니다.
\S 공백 문자를 제외한 모든 문자와 매치됩니다. \S+는 공백이 없는 단어들과 매치됩니다.
.findall()은 문자열 전체를 검색해서 매칭된 결과만 모아 리스트로 반환하는 함수
[]는 패턴, findall()은 그 패턴을 이용해서 문자열 안에서 찾아 리스트로 내줌.

 

.[dot] 문자 - \n을 제외한 모든 문자

 \n(줄바꿈)을 제외한 임의의 한 문자와 매칭 합니다.

도트 문자의 정규식 문자열 매치 여부 및 설명
a.b aab "aaa"는 가운데 문자 "a"가 모든 문자를 의미 하는 .과 일치 하므로 정규식과 매치가 됩니다.
a0b "a0b"는 가운데 문자"0"가 모든 문자를 의미하는 .과 일치하므로 정규식과 매치가 됩니다.
abc "abc"는 "a"와 "b"문자 사이에 어떤 문자라도 하나는 있어야 정규식과 일치하는데 없으므로 매치되지 않습니다.
정규표현식 a.b는 a와b 사이에 임의 문자 1개가 오는 경우 매칭을 한다는 의미입니다.

 

 

a.b가 아닌 다른 방식을 잘못 사용했을 때의 예시입니다.

a[.]b
# 대괄호 안의 .(점)은 메타문자가 아니라 문자 그대로 '.'을 의미.
# 따라서 'a.b'라는 문자열에만 매칭됨.
# 예시: "a.b" → 매칭, "aab" → 매칭 안 됨, "axb" → 매칭 안 됨

a+.+b
# 의미: a가 1번 이상 반복(+), 그 뒤 임의 문자(.), 그 다음 b
# 예시: "aab" → 매칭, "aaab" → 매칭, "a0b" → 매칭, "a.b" → 매칭
# (중간에 어떤 문자든 1개만 오면 모두 매칭)

 

 

*, +, ?, {m,n} [반복]문자

*는 0회 이상 반복을 의미합니다(바로 앞 문자가 0번 이상 반복될 때와 매치)

*정규식 문자열 매치 여부 및 설명
ca*t ct "a"가 0회 이상 반복되어 매치(0번)
cat "a"가 0회 이상 반복되어 매치(1번 반복)
caaat "a"가  0번 이상 반복되어 매치(3번 반복)

+는 1회 이상 반복을 의미합니다(바로 앞 문자가 1번 이상 반복될 때와 매치)

+정규식 문자열 매치 여부 및 설명
ca+t ct "a"가 1회 이상 반복되지 않으므로 매치 불가
cat "a"가 1회 이상 반복되어 매치(1회)
caaat "a"가  1회 이상 반복되어 매치(3번 반복)

?는 0회 또는 1을 의미합니다(바로 앞 문자가 0번 또는 1번 나타날 때와 매치)

?정규식 문자열 매치 여부 및 설명
ca?t ct "a"가 0번 사용되어 매치
cat "a"가 1번 사용되어 매치
caaat "a"가  3번 사용되어 매치 불가 

{m,n}은 m회 이상, n회 이하 반복합니다(바로 앞 문자가 m번이상, n번 이하 반복될 때와 매치)

{m,n}정규식 문자열 매치 여부 및 설명
ca{2,5}t cat "a"가 1번만 반복되어 매치 불가
caat "a"가 2번 반복되어 매치
caaaaat "a"가 5번 반복되어 매치

 

간단한 예제로 실습을 해보겠습니다.

 

앵커 - ^, $ [문자열의 시작과 끝]

^는 문자열의 시작을 의미합니다.

$는 문자열의 끝을 의미합니다.

앵커 정규식 설명
^abc 문자열이 abc로 시작해야 매치 됩니다.
xyz$ 문자열의 끝이 xyz로 끝나야 매치 됩니다.

간단한 예제 입니다.

bool을 사용하여 bool값으로 변환하여 결과를 확인 하겠습니다.

bool을 사용한 이유는 True/False로 값을 단순히 확인하기 위해 사용
bool()을 안 써도 조건문에서는 True/False처럼 동작

 

파이프 | (or)

|는 여러 패턴 중 한가지와 매치하겠다는 의미 입니다.

파이프 정규식 설명
a|b "a"또는"b"가 나오면 매치 됩니다.

간단한 예제 입니다.

 

이스케이프 \

\(역슬래시)는 메타문자를 그대로 사용하기 위한 문자입니다.

간단한 예제로 확인하겠습니다.

 

 

▶파이썬의 re모듈

파이썬은 re 모듈을 통해 정규식을 지원 합니다.

정규식을 사용하려면 먼저 import re를 사용하여 모듈을 불러와야 합니다.

re 모듈은 정규식을 활용한 검색, 치환, 분리, 컴파일 기능을 제공합니다.

re모듈에는 아래와 같은 함수들이 있습니다.

 

re.match() 

match함수는 문자열의 처음부터 정규식과 일치하는지 확인하는 함수입니다.

일치 할시 Match 객체로 반환, 아니면 None으로 반환 합니다.

span =(0,3)의 의미는 0번 인덱스에서 시작해서 3번 인덱스 전 까지의 문자열이 매칭되었다는 의미입니다.

 

re.search()

search함수는 문자열 전체에서 정규식이 처음 매칭되는 부분을 찾는 함수 입니다.

 

re.findall()

findall함수는 정규식과 매칭되는 모든 결과를 리스트로 반환 하는 함수입니다( 지금까지 예제에서 사용해온 함수 입니다.)

re.finditer()

finditer 함수는 findall과 비슷하지만 리스트가 아닌 반복 가능한 객체(iterator)를 반환하는 함수 입니다.

이 이터레이터는 하나씩 Match 객체를 꺼내 쓸 수 있고, 필요할 때만 메모리를 사용합니다.

re.sub()

sub함수는 정규식과 일치하는 부분을 다른 문자열로 치환하는 함수 입니다.

 

re.split()

split함수는 정규식을 기준으로 문자열을 분리하는 함수입니다

.

 

re.compile() - 정규식 객체 만들기

compile함수는 자주쓰는 패턴은 미리 컴파일 해서 재사용 가능하게 해주는 함수입니다.

 

▶match객체의 메서드

re.match()나 re.search() 함수 또는 re.findall() 함수가 성공적으로 매치되면 Match 객체를 반환합니다.

이 객체에는 매치된 문자열과 그 위치 정보를 확인할 수 있는 메서드들이 있습니다.

 

.group()

group메서드는 매칭된 문자열을 반환하는 메서드입니다.

 

.start()

start메서드는 매칭된 문자열의 시작인덱스를 반환 하는 메서드 입니다.

 

.end()

end메서드는 매칭된 문자열의 끝 인덱스를 반환 합니다.

.span()

span메서드는 매칭된 문자열의 시작, 끝 인덱스를 튜플로 반환 합니다.

 

▶컴파일 옵션

정규식을 사용할 때 re.I (무시), re.M (여러 줄 매치)와 같은 컴파일 옵션을 사용할 수 있습니다.

re.compile() 로 정규식을 정규식 객체로 만들 때, 추가로 설정할 수 있는 동작 모드(플래그, flag) 가 바로 컴파일 옵션입니다.

즉, “이 정규식을 어떻게 해석할지”를 조절하는 스위치 같은 역할을 합니다.

아래와 같은 옵션이 있습니다.

 

re.I 또는 re.IGNORECASE

대소문자를 구분하지 않고 매칭하는 컴파일 옵션 입니다.

 

 

re.M 또는 re.MULTILINE

여러 줄 문자열에서 ^,$ 앵커가 각 줄의 시작과 끝에 적용되는 컴파일 옵션 입니다.

 

re.S 또는 re.DOTALL

.(dot)메타문자가 줄바꿈 문자(\n)까지 포함해서 매칭하는 컴파일 옵션 입니다.

 

re.X 또는 re.VERBOSE

정규식을 여러 줄에 걸려 보기 좋게 작성 가능하며 공백 및 주석을 무시(공백 및 주석 포함)하는 컴파일 옵션 입니다.

 

▶역슬래시 문제(\)

파이썬 문지열과 정규식 모두 역슬래시(\)를 이스케이프 문자로 사용하기 때문에 혼란이 생길 수 있습니다.

이를 해결하기 위해raw string을 사용합니다. 문자열 앞에 r을 붙이면 됩니다.

문제의 원인 역슬래시(\) 설명
파이썬 문자열 \n(줄바꿈), \t(탭), \b(백스페이스) 등
이스케이프 문자로 사용됨.
두 시스템이 모두 \를 쓰다보니 충돌이 발생
정규표현식 \d(숫자), \s(공백), \b(단어 경계) 등
패턴 지정에 사용됨.

이 문제를 해결 하기 위해 파이썬의 정규 표현식에는 항상 r을 붙여 사용하면 되겠습니다.

이게 Raw String입니다.

문자열 앞에 r을 붙이면 파이썬은 역슬래시를 해석하지 않고 그대로 정규식 엔진에 전달하게 됩니다.

 

▶문자열 소비가 없는 메타문자

정규식에서는 대부분의 메타문자는 문자열을 소비(consume)합니다.

예를 들면 a+는 실제로 문자열에서 aaa를 차지하고 매칭 합니다.

 

하지만, 몇몇 메타문자는 문자열을 차지하지 않고, 위치나 조건만 확인 합니다.

이를 문자열 소비가 없는 메타문자라고 합니다.

 

아래와 같은 메타문자가 있습니다.

 

파이프(|) : OR 조건

여러 패턴 중 하나와 매칭 됩니다.

문자열을 소비하긴 하지만, 분기(선택) 역할로 주로 설명됩니다.

import re

print(re.findall(r"cat|dog", "cat dog catalog"))  
# ['cat', 'dog', 'cat']

 

앵커 문자 (^, $)

문자열을 차지하지 않고 위치만 지정합니다.

import re

print(bool(re.search(r"^Hello", "Hello Python")))  # True
print(bool(re.search(r"world$", "Hello world")))   # True

 

단어 경계 (\b, \B)

문자열을 차지하지 않고, 단어의 경계 여부만 확인합니다.

r"\b"는 단어경계(word boundary)로 

“단어 문자(영문자, 숫자, 밑줄 _)와 비-단어 문자(공백, 구두점 등) 사이”를 의미합니다.

실제 문자를 소비하지 않고 위치만 표시합니다.

import re

print(bool(re.search(r"\bcat\b", "a cat is here")))   # True (단어 cat만 매칭)
print(bool(re.search(r"\bcat\b", "concatenate")))     # False (단어 중간이라 경계 아님)

 

r"\B"는 단어 경계가 아님 (non-word boundary)으로

\b의 반대. 단어 문자 사이, 또는 비-단어 문자 사이 같은 경계가 아닌 위치를 의미합니다.

import re
print(bool(re.search(r"\Bcat\B", "concatenate")))   # True (중간에 cat → 앞뒤가 단어문자)
print(bool(re.search(r"\Bcat\B", "a cat ")))        # False (앞뒤가 공백이라 경계에 걸림)

 

문자열의 시작과 끝(\A. \Z)

r"\A"는 문자열의 시작을 나타냅니다.

^와 비슷하지만, 문자열 전체의 시작 위치만 의미하며 여러 줄 모드(re.M)에서도 변하지 않고, 무조건 맨 처음만 봅니다.

(^는 각 줄 시작도 매칭, \A는 문자열 맨 앞만 매칭)

import re

text = """Hello
Python"""

print(bool(re.search(r"^Hello", text, re.M)))  # True (줄 단위 시작도 매칭)
print(bool(re.search(r"\AHello", text, re.M))) # True (문자열 맨 처음만 매칭)
r"\Z"는 문자열의 끝을 나타냅니다.

$와 비슷하지만, 문자열 전체의 끝만 의미하며 여러 줄 모드(re.M)에서도 변하지 않고, 무조건 마지막만 봅니다.

($는 각 줄 끝도 매칭, \Z는 문자열 맨 끝만 매칭)

text = """Hello
Python"""

print(bool(re.search(r"Python$", text, re.M)))  # True (줄 끝도 매칭)
print(bool(re.search(r"Python\Z", text, re.M))) # True (문자열 마지막만 매칭)

 

▶그루핑 (Grouping)

정규 표현식에서 () (소괄호)는 그루핑에 사용됩니다
즉, 패턴 일부를 묶어서 하나의 단위로 취급하거나, 나중에 재참조
할 수 있습니다.

조금 더 쉽게 말해서 소괄호를 사용하여 패턴의 일부를 그룹으로 묶는 기능입니다.

 

그루핑에는 두가지 역할이 있습니다.

 

패턴 묶기 (Grouping)과 결과 추출 (Capturing)입니다.

그루핑의 가장 기본적인 역할은 여러 문자를 하나의 단위로 묶어주는 것 입니다.

이렇게 묶인 그룹에 *나 +와 같은 수량자를 적용하면, 그룹 전체를 한 번에 반복시킬 수 있습니다.

이걸 패턴 묶기(Grouping)이라고 합니다.

예를 들어, abc는 'a','b','c'가 각각 독립적 문자 입니다. 하지만, 소괄호를 사용하여 (abc)+를 묶어주면 abc라는 패턴 전체가 하나의 그룹이 되어, 이 그룹이 1번 이상 반복되는 것을 의미하게 됩니다. 이 패턴은 'abc', 'abcabc', 'abcabcabc' 등과 매치됩니다.  

 

그루핑의 또 다른 중요한 역할은 정규식 검색 결과에서 특정 부분을 따로 추출하는 것입니다. 소괄호로 묶인 각 그룹은 순서대로 번호가 매겨져, 매치된 문자열 중 원하는 부분만 쉽게 꺼낼 수 있습니다. 이걸 결과 추출 (Capturing)이라고 합니다

예를 들어, '전화번호: 010-1234-5678'이라는 문자열에서 지역번호와 국번을 따로 추출하고 싶다면, 다음과 같이 그루핑을 사용할수 있습니다.

 

group(인덱스) 설명
group(0) 또는 group() 매치된 전체 문자열
group(1) 첫 번째 그룹에 해당되는 문자열
group(2) 두 번째 그룹에 해당하는 문자열
group(n) n번째 그룹에 해당하는 문자열
groups() 소괄호로 묶인 모든 그룹의 결과를 튜플로 한번에 반환

 

그루핑은 이미 매칭된 그룹을 다시 참조하여 그룹 문자열을 재참조 (backreference) 도 할 수 있습니다.

정규식 안에서 \숫자 형식으로 사용합니다.

(\b\w+)가 첫 번째 단어를 매칭했고, \1은 그 단어를 다시 참조

 

또한, 그룹에 이름을 붙여 (named group) 숫자 대신 이름으로 참조도 가능합니다. 

문법은 (?P<이름>패턴)이며 참조할 때는 (?P=이름)입니다.

그루핑을 표로 정리하면 

기능 문법 예시
그룹핑 (패턴) (\d{3})-(\d{4})
그룹 참조 \숫자 (\w+)\s+\1
그룹 이름 붙이기 (?P<이름>패턴) (?P<area>\d{3})
이름으로 재참조 (?P=이름) (?P<word>\w+)\s+(?P=word)

이렇게 되겠습니다.

 

▶ 전방 탐색 (Lookahead)

전방 탐색은 정규 표현식에서 조건만 확인하고 실제 문자열은 소비하지 않는 메타문자입니다.
즉, 특정 패턴이 뒤에 오는지/오지 않는지 검사만 합니다.

 

긍정형 전방 탐색 (?=...)

... 패턴이 뒤에 오는 경우만 매칭되며 문자열을 소비하지 않고 위치만 확인합니다.

'http'중에서 뒤에s가 붙은 경우만 매칭됩니다
"https"는 http 매칭,"httpx"는 매칭 안 됨 

부정형 전방 탐색 (?!...)

... 패턴이 뒤에 오지 않는 경우만 매칭되며 역시 문자열은 소비하지 않고 조건만 확인합니다.

'http'중에서 뒤에s가 없는 경우만 매칭됩니다
"https"는 매칭이 안됨,"http"는 매칭 

 

 

▶ 문자열 바꾸기 re.sub()

re.sub() 함수는 위에서 배웠으나 한번 더 설명하면 정규식과 일치하는 부분을 다른 문자열로 치환합니다.

이 부분에서 배울 건 참조 구문 사용하기와 함수 넣기 입니다.

우선, re.sub()의 간단한 기본 사용법 입니다.

import re

text = "one two three"
result = re.sub(r"one", "1", text) #"one"을 "1"로 바꿈
print(result)  # 1 two three

 

참조 구문 사용하기 (\숫자)

()로 그룹핑한 문자열을 \1, \2처럼 치환 문자열에서 다시 참조할 수 있습니다.

뒤의 네 자리(\3)를****로 치환

 

함수 넣기

re.sub의 두 번째 인자로 함수를 넣을 수도 있으며 함수는 매칭 객체(Match)를 받아서 원하는 값으로 변환한 문자열을 반환합니다.

매칭된 결과를 함수에서 가공해 치환할 수 있다

 

간단하게 re.sub를 표로 정리하면 아래와 같습니다.

re. sub기능 문법 설명
기본 치환 re.sub(패턴, "문자열", 대상) 단순 치환
그룹 참조 \1, \2 ... 그룹핑한 문자열을 참조하여 치환
함수 사용 re.sub(패턴, 함수, 대상) 매칭 결과를 가공해서 치환

 

유사메서드

re.sub와 유사한 메서드인 re.subn()이라는 메서드가 있습니다.

sub()처럼 문자열을 치환하지만, 결과를 (치환된 문자열, 치환 횟수) 튜플로 반환한다는 차이가 있습니다.

sub() 는치환된 문자열만 반환, subn()는 (치환된 문자열, 치환 횟수) 반환한다는 차이입니다.

 

 

 

▶greedy와 non-greedy

정규 표현식에서 *, +, ?, {m,n} 같은 반복 메타문자는 기본적으로 탐욕적(greedy) 이며 조건을 만족하는 한 가능한 많이 매칭하려 합니다.

반대로, 비탐욕적(non-greedy, 최소 반복) 모드는 가능한 적게 매칭하며 이때는 메타문자 뒤에 ?를 붙입니다.

 

Greedy (탐욕적)

가능한 많이 매칭합니다.

 

<tag>부터 마지막</tag>까지 한 번에 다 먹어버림

 

Non-greedy (비탐욕적)

메타문자 뒤에 ?를 붙여 최소 반복합니다.

<tag>...</tag>를 각각 최소 단위로 매칭.

 

간단한 정리 입니다.

모드 문법 의미 예시 결과
Greedy *, +, {m,n} 가능한 한 많이 매칭 한 덩어리 전체
Non-greedy *?, +?, {m,n}? 가능한 한 적게 매칭 최소 단위별

 

 

이것으로 파이썬의 정규표현식에 대해 마치겠습니다.

고생하셨습니다😌

 

📘 참고:
《Do it! 점프 투 파이썬 (전면 개정 2판)》, 박응용 저, 이지스퍼블리싱, 2023
※ 본 글은 위 교재의 내용을 학습 및 정리 목적으로 요약/재구성한 글입니다.

반응형