[Python] 정규표현식 (Regular Expression ; Regex)

이 글은 파이썬에서 정규표현식을 사용하는 방법에 관한 기록입니다.

1. 정규표현식 개념

정규표현식(Regular Expression ; Regex)은 패턴(규칙)을 갖는 문자열의 집합을 표현하는 데에 사용되는 기법입니다. 주로 복잡한 문자열에서 특정한 패턴과 일치하는 문자열을 찾고 대체하기 위해서 사용하여 복잡한 문자열을 처리할 때 매우 유용합니다.

많은 프로그래밍 언어에서 정규표현식 기능을 지원하고 있는데, 정규표현식 문법에 있어서는 약간씩 차이가 존재합니다.

2. 메타 문자 (Meta characters)

메타 문자는 문자가 가진 원래의 의미가 아닌 특별한 용도로 사용되는 문자를 말합니다. 정규표현식에서 사용되는 메타 문자는 다음과 같습니다.

. ^ $ * + ? \ | ( ) { } [ ]  

3. 정규표현식 문법

패턴 설명
\w 영어 소문자, 영어 대문자, 숫자, _(언더바)
\W \w의 반대
\d 숫자
\D \d의 반대 = 숫자 제외 모든 문자
\s 공백, 탭 (\t), 줄바꿈(\r\n)
\S \S의 반대 = 공백, 탭, 줄바꿈 제외 모든 문자
. 모든 문자 (공백 포함, 줄바꿈 제외)
| | 앞뒤 패턴을 or 조건으로 지정
[] [] 안 패턴을 or 조건으로 지정
[0-9] 숫자
[a-z] 영어 소문자
[A-Z] 영어 대문자
[ㄱ-ㅣ] 한글 자음 및 모음
[가-힣] 한글 문자
[^] 대괄호 안 패턴 제외
^ 패턴의 시작 위치 지정
$ 패턴의 끝 위치 지정
+ 앞 패턴이 1~무한대번 연속 일치
* 앞 패턴이 0~무한대번 연속 일치
? 앞 패턴이 0~1번 일치 = 있거나 없거나
{n} 앞 패턴이 n번 연속 일치
{n,} 앞 패턴이 n~무한대 연속 일치
{n,m} 앞 패턴이 n~m번 연속 일치 (n<m)
A(?=B) 패턴A 뒤의 문자열이 패턴B와 일치하면 패턴A 지정 (전방탐색)
A(?!B) 패턴A 뒤의 문자열이 패턴B와 일치하지 않으면 패턴A 지정
(?<=A)B 패턴B 앞의 문자열이 패턴A와 일치하면 패턴B 지정 (후방탐색)
(?<!A)B 패턴B 앞의 문자열이 패턴A와 일치하지 않으면 패턴B 지정

4. 정규표현식 with 파이썬

파이썬에서는 re 패키지 통해 정규표현식을 사용할 수 있습니다.

import re

re.compile()을 통해 정규표현식을 컴파일하여 사용할 수 있습니다.

p = re.compile('[a-z]+')

re.compile()은 패턴 객체를 반환합니다.

print(type(p))
<class '_sre.SRE_Pattern'>

Pattern 객체의 메소드

패턴 객체에는 다음과 같은 네개의 메소드가 있습니다.

메소드 설명
match 전체 문자열에서 시작부터 패턴과 일치하는 첫번째 문자열을 찾아 매치 객체로 반환
search 전체 문자열에서 패턴과 일치하는 첫번째 문자열을 찾아 매치 객체로 반환
findall 전체 문자열에서 패턴과 일치하는 모든 문자열을 찾아 리스트로 반환
finditer 전체 문자열에서 패턴과 일치하는 모든 문자열을 찾아 반복 가능 객체로 반환

match() : 시작부터 패턴과 일치하는 첫번째 문자열 찾기

match()는 전체 문자열에서 시작부터 패턴과 일치하는 첫번째 문자열을 찾아 매치 객체로 반환합니다. match()는 반드시 문자열의 처움부터 일치해야만 이를 매치 합니다.

문자열 “abc”는 “a” 즉 영어 소문자로 시작하므로 매치 되는 것을 확인할 수 있습니다.

p = re.compile('[a-z]+')
string = 'abc'
result = p.match(string)
print(result)
<_sre.SRE_Match object; span=(0, 4), match='abc'>

문자열 “abc”는 “a’” 즉 영어 소문자로 시작하고 문자열 중간에 “2” 즉 패턴과 달리 숫자가 있으므로 “2” 전까지 매치 되는 것을 확인할 수 있습니다.

p = re.compile('[a-z]+')
string = 'abcd2ab'
result = p.match(string)
print(result)
<_sre.SRE_Match object; span=(0, 4), match='abcd'>

문자열 “9abc”는 “9” 즉 패턴과 달리 숫자로 시작하므로 매치 되지 않아 None을 반환하는 것을 확인할 수 있습니다.

p = re.compile('[a-z]+')
string = '9abc'
result = p.match(string)
print(result)
None

serch() : 패턴과 일치하는 첫번째 문자열 찾기

serch() 는 전체 문자열에서 패턴과 일치하는 첫번째 문자열을 찾아 매치 객체로 반환합니다. 반드시 문자열의 처움부터 일치해야 하는 match()와는 달리, search()는 문자열의 중간에라도 일치하는 패턴이 있다면 이를 매치 합니다.

p = re.compile('[a-z]+')
string = 'abc'
result = p.search(string)
print(result)
<_sre.SRE_Match object; span=(0, 4), match='abc'>

문자열 “abc”는 “a” 즉 영어 소문자로 시작하므로 매치 되는 것을 확인할 수 있습니다.

p = re.compile('[a-z]+')
string = 'abcd2ab'
result = p.search(string)
print(result)
<_sre.SRE_Match object; span=(0, 4), match='abcd'>

문자열 “abc”는 “a’” 즉 영어 소문자로 시작하고 문자열 중간에 “2” 즉 패턴과 달리 숫자가 있으므로 “2” 전까지 매치 되는 것을 확인할 수 있습니다.

p = re.compile('[a-z]+')
string = '9abc'
result = p.search(string)
print(result)
None

문자열 “9abc”는 “9” 즉 패턴과 달리 숫자로 시작하므로

findall() : 패턴과 일치하는 모든 문자열 찾기

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

p = re.compile('[a-z]+')
string = 'abc'
result = p.findall(string)
print(result)
['abc']
p = re.compile('[a-z]+')
string = 'abcd2ab'
result = p.findall(string)
print(result)
['abcd', 'ab']

finditer() : 패턴과 일치하는 모든 문자열을 찾기

finditer()는 전체 문자열에서 패턴과 일치하는 모든 문자열을 찾아 반복 가능 객체로 반환합니다.

p = re.compile('[a-z]+')
string = 'abc'
result = p.finditer(string)
print(result)
<callable_iterator object at 0x102cf2898>
p = re.compile('[a-z]+')
string = 'abcd2ab'
result = p.finditer(string)
for i in result:
    print(i)
<_sre.SRE_Match object; span=(0, 4), match='abcd'>
<_sre.SRE_Match object; span=(5, 7), match='ab'>

Match 객체 메소드

매치 객체는 아래와 같은 구조를 가집니다.

<_sre.SRE_Match object; span=(매치 시작 인덱스, 매치 끝 인덱스), match='매치 된 문자열'>

각 정보에 접근할 수 있도록, 매치 객체에는 다음과 같은 네개의 메소드가 있습니다.

메소드 설명
group() 매치 된 문자열 반환
start() 매치 시작 인덱스 반환
end() 매치 끝 인덱스 반환
span() (매치 시작 인덱스, 매치 끝 인덱스) 형태의 튜플 반환
p = re.compile('[a-z]+') # 패턴 객체
string = 'abcd2ab'
result = p.match(string) # 매치 객체
print(result)
<_sre.SRE_Match object; span=(0, 4), match='abcd'>
# 매치 된 문자열 출력
print(result.group())
abcd
# 매치 시작 인덱스 출력
print(result.start())
0
# 매치 끝 인덱스 출력
print(result.end())
4
# (매치 시작 인덱스, 매치 끝 인덱스) 형태 튜플 출력
print(result.span())
(0, 4)

참고자료

re Documentation

태그:

카테고리:

업데이트:

댓글남기기