[Python] 정규표현식(4) - COMPILE 옵션 - (DOTALL, IGNORECASE, MULTILINE, VERBOSE)

미남로그·2021년 9월 14일
0
post-custom-banner

저는 점프투파이썬 교재로 공부합니다. 이 교재를 바탕으로 공부한 걸 정리합니다.

정규 표현식 시리즈

1️⃣ 정규표현식이란? 문자 클래스, Dot(.), 반복(*), 반복(+), 반복({m,n}, ?)
2️⃣ 정규 표현식(2) - 문자열 검색(match, search, findall, finditer)
3️⃣ 정규표현식(3) - match 객체의 메서드(group, start, end, span)
4️⃣ 정규표현식(4) - COMPILE 옵션 - (DOTALL, IGNORECASE, MULTILINE, VERBOSE)
5️⃣ 정규 표현식(5) - 백슬래시 문제('\n')
6️⃣ 정규 표현식(6) 메타 문자 - |, ^, $, \A, \Z, \b, \B
7️⃣ 정규표현식(7) 그루핑, 전방 탐색, 문자열 바꾸기, Greedy vs Non-Greedy



모듈 단위 수행

p = re.compile('[a-z]+')
m = p.match("python")

이때까지 re.compile을 사용하여 컴파일된 패턴 객체로 그 이후의 작업을 수행했습니다.

re 모듈은 더 축약한 형태로 사용이 가능합니다! 위의 코드는 이렇게 표현될 수 있습니다.

m = re.match('[a-z]+', "python")

컴파일과 match 메서드를 한 번에 수행 가능합니다. 보통 한 번 만든 패턴 객체를 여러 번 사용해야 할 때는 이 방법보다 re.compile을 사용하는 것이 편합니다!


컴파일 옵션

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

옵션 이름약어설명
DOTALLSdot 문자(.)가 줄바꿈 문자를 포함하여 모든 문자와 매치한다.
IGNORECASEI대소문자에 관계없이 매치한다.
MULTILINEM여러 줄과 매치한다. (^, $ 메타 문자의 사용과 관계가 있는 옵션이다.
VERBOSEXverbose 모드를 사용한다. (정규식을 보기 편하게 만들 수도 있고 주석 등을 사용할 수도 있다.)

옵션을 사용할 때는 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

문자열과 정규식이 매치되지 않는다는 것을 알 수 있습니다.

import re
p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)

<re.Match object; span=(0, 3), match='a\nb'>

보통 re.DOTALL 옵션은 여러 줄로 이루어진 문자열에서 \n과 상관없이 검색할 때 많이 사용합니다.


IGNORECASE, I

re.IGNORECASE 또는 re.I 옵션은 대소문자 구별 없이 매치를 수행할 때 사용하는 옵션입니다.

import re
p = re.compile('[a-z]', re.I)
print(p.match('python'))
print(p.match('Python'))
print(p.match('PYTHON'))

<re.Match object; span=(0, 1), match='p'>
<re.Match object; span=(0, 1), match='P'>
<re.Match object; span=(0, 1), match='P'>

[a-z] 정규식은 소문자만을 의미하지만 re.I 옵션으로 대소문자 구별 없이 매치된다.


MULTILINE, M

re.MULTILINE 또는 re.M 옵션은 메타 문자인 ^, $와 연관된 옵션이다.

^ 메타 문자는 문자열의 처음을 의미하고 $는 문자열의 마지막을 의미합니다.

예를 들어, 정규식이 '^python'인 경우 문자열의 처음은 항상 python으로 시작해야 매치되고, 만약 정규식이 'python$'이라면 문자열의 마지막은 항상 python으로 끝나야 매치된다는 의미입니다.

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, 그 뒤에 단어가 와야 한다는 의미입니다.

검색할 문자열 data는 여러 줄로 이루어져 있습니다.

^ 메타 문자에 의해 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.MULTILINE만 추가해주었더니 'python'으로 시작하는 각 줄의 문자열이 매치됩니다.

re.MULTILINE 옵션은 ^, $ 메타 문자를 문자열의 각 줄마다 적용해 주는 것이니다.


VERBOSE, X

지금까지 만든 정규식은 매우 간단하지만, 전문가들이 만든 정규식은 거의 암호 수준이라 책에서 언급합니다.(공감합니다ㅋㅋㅋㅋㅋㅋㅋㅋㅋ)

이렇게 이해하기 어려운 정규식을 주석 또는 줄 단위로 구분해주는 방법이 있다는데, 그게 바로 re.VERBOSE 또는 re.X 입니다.

charref = re.compile(r'&[#](0[0-7]+:[0-9]+:x[0-9a-fA-F]+);')

이 정규식이 이해 가십니까?

charref = re.compile(r"""
&[#] # Start of a numeric entity reference
(
0[0-7]+ # Octal form
:[0-9]+ # Decimal form
:x[0-9a-fA-F]+ # Hexadecimal form
)
; # Training semicolon
""", re.VERBOSE)

첫 번째와 두 번째 예를 비교해보면 컴파일된 패턴 객체인 charref는 모두 동일한 역할을 합니다.

하지만 정규식이 복잡할 경우 두 번째처럼 주석을 적고 여러 줄로 표현하는 것이 훨씬 가독성이 좋습니다.

re.VERBOSE 옵션을 사용하면 문자열에 사용된 whitespace는 컴파일 할 때 제거됩니다.

그리고 줄 단위로 # 기호를 사용하여 주석문을 작성하면 됩니다.

profile
미남이 귀엽죠
post-custom-banner

0개의 댓글