저는 점프투파이썬 교재로 공부합니다. 이 교재를 바탕으로 공부한 걸 정리합니다.
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을 사용하는 것이 편합니다!
정규식을 컴파일할 때 다음 옵션을 사용할 수 있습니다.
옵션 이름 | 약어 | 설명 |
---|---|---|
DOTALL | S | dot 문자(.)가 줄바꿈 문자를 포함하여 모든 문자와 매치한다. |
IGNORECASE | I | 대소문자에 관계없이 매치한다. |
MULTILINE | M | 여러 줄과 매치한다. (^, $ 메타 문자의 사용과 관계가 있는 옵션이다. |
VERBOSE | X | verbose 모드를 사용한다. (정규식을 보기 편하게 만들 수도 있고 주석 등을 사용할 수도 있다.) |
옵션을 사용할 때는 re.DOTALL처럼 전체 옵션 이름을 써도 되고 re.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과 상관없이 검색할 때 많이 사용합니다.
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 옵션으로 대소문자 구별 없이 매치된다.
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 옵션은 ^, $ 메타 문자를 문자열의 각 줄마다 적용해 주는 것이니다.
지금까지 만든 정규식은 매우 간단하지만, 전문가들이 만든 정규식은 거의 암호 수준이라 책에서 언급합니다.(공감합니다ㅋㅋㅋㅋㅋㅋㅋㅋㅋ)
이렇게 이해하기 어려운 정규식을 주석 또는 줄 단위로 구분해주는 방법이 있다는데, 그게 바로 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는 컴파일 할 때 제거됩니다.
그리고 줄 단위로 # 기호를 사용하여 주석문을 작성하면 됩니다.