파이썬은 정규 표현식을 지원하기 위해 re(regular expression) 모듈을 제공한다.
re 모듈은 파이썬을 설치할 때 자동으로 설치되는 기본 라이브러리다.
import re
p = re.compile('ab*')
re.compile을 사용하여 정규 표현식을 컴파일한다. re.compile의 결과로 돌려주는 객체 p(컴파일된 패턴 객체)를 사용하여 그 이후의 작업을 수행할 것이다.
컴파일된 패턴 객체는 다음과 같은 4가지 메서드를 제공한다.
Method | 목적 |
---|---|
match() | 문자열의 처음부터 정규식과 매치되는지 조사한다. |
search() | 문자열 전체를 검색하여 정규식과 매치되는지 조사한다. |
findall() | 정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려준다. |
finditer() | 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려준다. |
import re
p = re.compile('[a-z]+')
m = p.match("python")
print(m)
<_sre.SRE_Match object at 0x01F3F9F8>
"python" 문자열은 [a-z]+ 정규식에 부합되므로 match 객체를 돌려준다.
import re
p = re.compile('[a-z]+')
m = p.match("3 python")
print(m)
None
"3 python" 문자열은 처음에 나오는 문자 3이 정규식 [a-z]+에 부합되지 않으므로 None을 돌려준다.
import re
p = re.compile('[a-z]+')
m = p.search("python")
print(m)
<_sre.SRE_Match object at 0x01F3FA68>
import re
p = re.compile('[a-z]+')
m = p.search("3 python")
print(m)
<_sre.SRE_Match object at 0x01F3FA30>
"python" 문자열에 search 메서드를 수행하면 match 메서드를 수행했을 떄와 동일하게 매치되지만, "3 python" 문자열의 경우 첫 번째 문자는 "3"이지만 search는 문자열의 처음부터 검색하는 것이 아닌 문자열 전체를 검색하기 때문에 "3" 이후의 "python" 문자열과 매치된다.
import re
p = re.compile('[a-z]+')
result = p.findall("life is too short")
print(result)
['life', 'is', 'too', 'short']
"list is too short"문자열의 'life', 'is', 'too', 'short' 단어를 각각 [a-z]+ 정규식과 매치해서 리스트로 돌려준다.
import re
p = re.compile('[a-z]+')
result = p.finditer("life is too short")
print(result)
<callable_iterator object at 0x01F5E390>
for r in result: print(r)
<_sre.SRE_Match object at 0x01F3F9F8>
<_sre.SRE_Match object at 0x01F3FAD8>
<_sre.SRE_Match object at 0x01F3FAA0>
<_sre.SRE_Match object at 0x01F3F9F8>
finditer는 findall과 동일하지만 그 결과로 반복 가능한 객체(iterator object)를 돌려준다. 반복 가능한 객체가 포함하는 각각의 요소는 match 객체이다.
Method | 목적 |
---|---|
group() | 매치된 문자열을 돌려준다. |
start() | 매치된 문자열을 시작 위치를 돌려준다. |
end() | 매치된 문자열의 끝 위치를 돌려준다. |
span() | 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다. |
import re
p = re.compile('[a-z]+')
m = p.match("python")
m.group()
'python'
m.start()
0
m.end()
6
m.span()
(0, 6)
match 메서드를 수행한 결과로 돌려준 match 객체의 start()의 결괏값은 항상 0일 수 밖에 없다. match 메서드는 항상 문자열의 시작부터 조사하기 때문이다.
만약 search 메서드를 사용했다면 start() 값은 다음과 같이 다르게 나온다.
import re
p = re.compile('[a-z]+')
m = p.search("3 python")
m.group()
'python'
m.start()
2
m.end()
8
m.span()
(2, 8)
모듈 단위로 수행하기
re 모듈은 축약한 형태로 사용할 수 있는 방법을 제공한다.p = re.compile('[a-z]+) m = p.match("python")
위 코드가 축약된 형태는 다음과 같다.
m = re.match('[a-z]+', "python")
정규식을 컴파일할 때 다음 옵션을 사용할 수 있다.
※ 옵션을 사용할 때는 re.DOTALL 처럼 전체 옵션 이름을 써도 되고 re.S처럼 약어를 써도 된다.
import re
p = re.compile('a.b')
m = p.match('a\nb')
print(m)
None
정규식이 a.b인 경우 문자열 a\nb는 매치되지 않음을 알 수 있다. \n 문자와도 매치되게 하려면 다음과 같이 re.DOTALL 옵션을 사용해야 한다.
import re
p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)
<_sre.SRE_Match object at 0x01FCF3D8>
보통 re.DOTALL 옵션은 여러 줄로 이루어진 문자열에서 \n에 상관없이 검색할 때 많이 사용한다.
import re
p = re.compile('[a-z]', re.I)
p.match('python')
<_sre.SRE_Match object at 0x01FCFA30>
p.match('Python')
<_sre.SRE_Match object at 0x01FCFA68>
p.match('PYTHON')
<_sre.SRE_Match object at 0x01FCF9F8>
[a-z] 정규식은 소문자만을 의미하지만 re.I 옵션으로 대소문자 구별 없이 매치된다.
import re
p = re.compile("^python\s\w+")
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data))
['python one']
정규식 ^python\s\w+ 은 python이라는 문자열로 시작하고 그 뒤에 whitespace, 그 뒤에 단어가 와야 한다는 의미다.
스크립트르 실행하면 ['python one']의 결과를 돌려준다.
^ 메타 문자에 의해 python이라는 문자열을 사용한 첫 번째 줄만 매치 됐다.
각 라인의 처음으로 인식시키고 싶을 경우에는 re.MULTILINE 또는 re.M을 사용하면 된다.
import re
p = re.compile("^python\s\w+", re.MULTILINE)
data = """python one
life is too short
python two
you need python
python three"""
print(p.findall(data))
['python one', 'python two', 'python three']
re.VERBOSE 옵션을 사용하면 문자열에 사용된 whitespace는 컴파일할 때 제거된다(단, [] 안에 사용한 whitespace는 제외). 그리고 줄단위로 #기호를 사용하여 주석문을 작성할 수 있다.
예를들어 어떤 파일 안에 있는 "\section" 문자열을 찾기 위한 정규식을 만든다고 가정해보자.
\section
이 정규식은 \s 문자가 whitespace로 해석되어 의도한 대로 매치가 이루어지지 않는다.
위 표현은 다음과 동일한 의미이다.
[ \t\n\r\f\v]ection
의도한 대로 매치하고 싶다면 다음과 같이 변경해야 한다.
\\section
즉, 위 정규식에서 사용한 \ 문자가 문자열 자체임을 알려 주기 위해 백슬래시 2개를 사용하여 이스케이프 처리를 해야 한다.
그런데 여기서 또 하나의 문제가 발견된다. 위처럼 정규식을 만들어서 컴파일하면 실제 파이썬 정규식 엔진에는 파이썬 문자열 리터럴 규칙에 따라 \이 \로 변경되어 \section이 전달된다.
결국 정규식 엔진에 \ 문자를 전달하려면 파이썬은 \\처럼 백슬래시를 4개나 사용해야 한다.
이러한 문제로 인해 파이썬 정규식에는 Raw String 규칙이 생겨나게 되었다. 즉 컴파일해야 하는 정규식이 Raw String임을 알려줄 수 있도록 파이썬 문법을 만든 것이다.
p = re.compile(r'\\section')