-
Chapter 07-2 정규 표현식 시작하기_3Do it! 점프 투 파이썬 2022. 6. 9. 18:55
컴파일 옵션
정규식을 컴파일할 때 다음 옵션을 사용할 수 있다.
옵션 이름 약어 설명 DOTALL S dot 문자(.)가 줄바꿈 문자를 포함하여 모든 문자와 매치한다. 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은 . 메타 문자와 매치되지 않기 때문이다. \n 문자와도 매치되게 하려면 다음과 같이 re.DOTALL 옵션을 사용해야 한다.
>>> 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 옵션은 대.소문자 구별 없이 매치를 수행할 때 사용하는 옵션이다. 다음 예제를 보자.
>>> p = re.compile('[a-z]', re.I)
>>> p.match('python')
<re.Match object; span=(0, 1), match='p'>
>>> p.match('Python')
<re.Match object; span=(0, 1), match='p'>
>>> p.match('PYTHON')
<re.Match object; span=(0, 1), match='p'>[a-z] 정규식은 소문자만을 의미하지만 re.I 옵션으로 대.소문자 구별 없이 매치된다.
MULTILINE, M
re.MULTILINE 또는 re.M 옵션은 조금 후에 설명할 메타 문자인 ^, $와 연관된 옵션이다. 이 메타 문자에 대해 간단히 설명하자면 ^는 문자열의 처음을 의미하고, $는 문자열의 마지막을 의미한다. 예를 들어 정규식이 '^pythone'인 경우 문자열의 처음은 항상 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\s\w+'은 python이라는 문자열로 시작하고 그 뒤에 whitespace, 그 뒤에 단어가 와야 한다는 의미이다. 검색할 문자열 data는 여러 줄로 이루어져 있다.
이 스크립트를 실행하면 다음과 같은 결과를 돌려준다.
['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))re.MULTILINE 옵션으로 인해 ^ 메타 문자가 문자열 전체가 아닌 각 줄의 처음이라는 의미를 갖게 되었다. 이 스크립트를 실행하면 다음과 같은 결과가 출력된다.
['python one', 'python two', 'python three'] 즉 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
)
; # Trailing semicolon
''', re.VERBOSE)첫 번째와 두 번째 예를 비교해 보면 컴파일된 패턴 객체인 charref는 모두 동일한 역할을 한다. 하지만 정규식이 복잡할 경우 두 번째처럼 주석을 적고 여러 줄로 표현하는 것이 훨씬 가독성이 좋다는 것을 알 수 있다.
re.VERBOSE 옵션을 사용하면 문자열에 사용된 whitespace는 컴파일할 때 제거된다.(단 [ ]안에 사용한 whitespace는 제외). 그리고 줄 단위로 #기호를 ㅅ용하여 주석문을 작성할 수 있다.
백슬래시 문제
정규 표현식을 파이썬에서 사용할 때 혼란을 주는 요소가 한 가지 있는데, 바로 백슬래시(\)이다.
예를 들어 어떤 파일 안에 있는 "\section" 문자열을 찾기 위한 정규식을 만든다고 가정해 보자.
\section 이 정규식은 \s 문자가 whitespace로 해석되어 의도한 대로 매치가 이루어지지 않는다.
위 표현은 다음과 동일한 의미이다.
[ \t\n\r\f\v]ection <- \s 문자가 이스케이프 코드 \t, \n, \r. \f, \v로 해석됨 의도한 대로 매치하고 싶다면 다음과 같이 변경해야 한다.
\\section 즉 위 정규식에서 사용한 \ 문자가 문자열 자체임을 알려 주기 위해 백슬래시 2개를 사용하여 이스케이프 처리를 해야 한다.
따라서 위 정규식을 컴파일하려면 다음과 같이 작성해야 한다.
>>> p = re.compile('\\section') 그런데 여기에서 또 하나의 문제가 발견된다. 위처럼 정규식을 만들어서 컴파일하면 실제 파이썬 정규식 엔진에는 파이썬 문자열 리터럴 규칙에 따라 \\이 \로 변경되어 \section이 전달된다.
결국 정규식 엔진에 \\ 문자를 전달하려면 파이썬은 \\\\처럼 백슬래시를 4개나 사용해야 한다.
>>> p = re.compile('\\\\section') 이렇게 해야만 원하는 결과를 얻을 수 있다. 하지만 너무 복잡하지 않은가?
만약 위와 같이 \를 사용한 표현이 계속 반복되는 정규식이라면 너무 복잡해서 이해하기 쉽지 않을 것이다. 이러한 문제로 인해 파이썬 정규식에는 Raw String 규칙이 생겨나게 되었다. 즉 컴파일해야 하는 정규식이 Raw String임을 알려 줄 수 있도록 파이썬 문법을 만든 것이다. 그 방법은 다음과 같다.
>>> p = re.compile(r'\\section') 위와 같이 정규식 문자열 앞에 r 문자를 삽입하면 이 정규식은 Raw String 규칙에 의하여 백슬래시 2개 대신 1개만 써도 2개를 쓴 것과 동일한 의미를 갖게 된다.
출처 : "점프 투 파이썬"
'Do it! 점프 투 파이썬' 카테고리의 다른 글
Chapter 07-3 강력한 정규 표현식의 세계로_2 (0) 2022.06.09 Chapter 07-3 강력한 정규 표현식의 세계로_1 (0) 2022.06.09 Chapter 07-2 정규 표현식 시작하기_2 (0) 2022.06.09 Chapter 07-2 정규 표현식 시작하기_1 (0) 2022.06.09 Chapter 07-1 정규 표현식 알아보기 (0) 2022.06.09