파이썬에서 정규 표현식을 지원하는 re 모듈

🖤devxyoon·2020년 10월 1일
0

파이썬은 정규 표현식을 지원하기 위해 re(regular expression) 모듈을 제공한다.
re 모듈은 파이썬을 설치할 때 자동으로 설치되는 기본 라이브러리다.

import re

p = re.compile('ab*')

re.compile을 사용하여 정규 표현식을 컴파일한다. re.compile의 결과로 돌려주는 객체 p(컴파일된 패턴 객체)를 사용하여 그 이후의 작업을 수행할 것이다.

정규식을 이용한 문자열 검색


컴파일된 패턴 객체는 다음과 같은 4가지 메서드를 제공한다.

Method목적
match()문자열의 처음부터 정규식과 매치되는지 조사한다.
search()문자열 전체를 검색하여 정규식과 매치되는지 조사한다.
findall()정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려준다.
finditer()정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려준다.

match


match 메서드는 문자열을 처음부터 정규식과 매치되는지 조사한다.
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" 문자열과 매치된다.

findall


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]+ 정규식과 매치해서 리스트로 돌려준다.

finditer


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 객체이다.

match 객체의 메서드


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")

컴파일 옵션


정규식을 컴파일할 때 다음 옵션을 사용할 수 있다.

  • DOTALL(S) - .이 줄바꿈 문자를 포함하여 모든 문자와 매치할 수 있도록 한다.
  • IGNORECASE(I) - 대소문자에 관계없이 매치할 수 있도록 한다.
  • MULTILINE(M) - 여러줄과 매치할 수 있도록 한다.
  • VERBOSE(X) - verbose 모드를 사용할 수 있도록 한다. (정규식을 보기 편하게 만들 수 있고 주석등을 사용할 수 있게 한다.)

※ 옵션을 사용할 때는 re.DOTALL 처럼 전체 옵션 이름을 써도 되고 re.S처럼 약어를 써도 된다.

DOTALL, S


. 메타 문자는 줄바꿈 문자(\n)를 제외한 모든 문자와 매치되는 규칙이 있다. 만약 \n 문자도 포함하여 매치하고 싶다면 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에 상관없이 검색할 때 많이 사용한다.

IGNORECASE, I


re.IGNORECASE 또는 re.I 옵션은 대소문자 구별 없이 매치를 수행할 때 사용하는 옵션이다.
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 옵션으로 대소문자 구별 없이 매치된다.

MULTILINE, M


re.MULTILINE 또는 re.M 옵션은 ^, $와 연관된 옵션이다.
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']

VERBOSE, X


정규식 전문가들이 만든 정규식을 보면 거의 암호수준이다. 정규식을 이해하려면 하나하나 조심스럽게 뜯어보아야만 한다. 이렇게 이해하기 어려운 정규식을 주석 또는 줄 단위로 구분할 수 있게 도와주는 것이 re.VERBOSE 또는 re.X 옵션이다.

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')
profile
서버는 죽지 않아요👼

0개의 댓글