안녕하세요~ 벌써 4월이 됐네요! 지난 주에는 개인 일이 있어서 포스팅을 한 주 쉬었습니다 고향에 내려가서 쉬었답니다! 🤣 이번 시간에는 정규표현식의 세 번째 포스팅을 하려 합니다. re.compile()을 사용함에 있어서 줄바꿈 문자를 포함하거나 문자열의 대소문자에 관계없이 매치할 수 있게 하는 등 여러 가지 옵션을 줄 수 있는 컴파일 옵션에 대해 알아보겠습니다!

컴파일 옵션

re.compile()의 다양한 옵션 중 아래 네 개에 대해 소개드리겠습니다.

  • re.DOTALL 또는 re.S : “.” 이 줄바꿈 문자를 포함하여 모든 문자와 매치

온점 (.)은 줄바꿈 문자인 “\n“을 제외한 모든 문자와 매치되는 규칙이 있습니다. 그런데 줄바꿈 문자와도 매치가 되고 싶다면 re.DOTALL이나 re.S 옵션을 사용하면 됩니다. 아래와 같이 “청.기”라는 문자열을 컴파일을 하고 “청소기”와 “청\n기”를 매치시킨다면 전자만 매치되고 후자는 매치되지 않습니다.

import re
a = re.compile("청.기")
b = a.match("청소기")
c = a.match("청\n기")
print('b :', b)
print('c :', c)
--------------------------------------------------------------------------------------------------------------------------------
b : <re.Match object; span=(0, 3), match='청소기'>
c : None

그러나 re.compile()을 실행할 때, 뒤에 re.DOTALL을 붙인다면 온점 (.)이 줄바꿈 문자와도 매치가 됩니다. 이 옵션은 여러 줄로 이루어진 문자열에서 줄바꿈 문자에 상관없이 검색할 때 많이 사용됩니다.

import re
a = re.compile("청.기", re.DOTALL)
d = a.match("청\n기")
print('d :', d)
--------------------------------------------------------------------------------------------------------------------------------
d : <re.Match object; span=(0, 3), match='청\n기'>


  • re.IGNORECASE 또는 re.I : 대소문자 구별 없이 매치

대소문자가 혼합되어 있을 때 유용하게 사용할 수 있습니다. 처음에 컴파일 할 때, “[a-zA-Z]+”로 하면 되지 않을까 생각도 듭니다

import re
a = re.compile("[a-z]+", re.I)
b = a.match("juice")
c = a.match("Juice")
d = a.match("JUICE")
print('b :', b)
print('c :', c)
print('d :', d)
--------------------------------------------------------------------------------------------------------------------------------
b : <re.Match object; span=(0, 5), match='juice'>
c : <re.Match object; span=(0, 5), match='Juice'>
d : <re.Match object; span=(0, 5), match='JUICE'>


  • re.MULTILINE 또는 re.M : ‘^’, ‘$’ 메타 문자를 문자열의 각 줄마다 적용

"^"는 문자열의 처음을 의미하고, '\$'는 문자열의 마지막을 의미합니다.

아래와 같이 띄어쓰기로 상당히 긴 글귀가 있습니다. 이 문자열에서 “^좋은\s\w+”인 문자열을 찾고 싶습니다. \s는 whitespace를 의미하고, \w는 문자+숫자+언더바를 의미합니다. 즉, ‘좋은’이라는 문자열 뒤에 whitespace가 오고 그 뒤에 오는 문자열을 매치시킨다는 뜻입니다. 아래에는 ‘좋은’으로 시작하는 문자열이 많지만 가장 첫 줄의 ‘좋은 기분으로’만 매치가 되었습니다. 이는 “^” 메타 문자가 문자열 전체의 처음을 뜻하기 때문입니다.

import re
a = re.compile("^좋은\s\w+")
b = """좋은 기분으로
시작한 하루가 많을수록
좋은 인생으로
언젠가 활짝 꽃필거야
좋은 하루 보내길 바랄게"""
print(a.findall(b))
--------------------------------------------------------------------------------------------------------------------------------
['좋은 기분으로']

이 때, re.MULTILINE 옵션을 주면 “^” 메타 문자가 각 라인의 처음으로 인식되게 됩니다. 따라서 줄마다 ‘좋은’으로 시작되는 문자열이 모두 매치되어 아래와 같이 3개의 문자열 결과가 도출됩니다.

import re
a = re.compile("^좋은\s\w+", re.MULTILINE)
c = """좋은 기분으로
시작한 하루가 많을수록
좋은 인생으로
언젠가 활짝 꽃필거야
좋은 하루 보내길 바랄게"""
print(a.findall(c))
--------------------------------------------------------------------------------------------------------------------------------
['좋은 기분으로', '좋은 인생으로', '좋은 하루']

’$’도 위의 결과와 비슷하게 도출됩니다.

import re
a = re.compile("\w+리$", re.MULTILINE)
d = """리 리 리자로 끝자는 말은
개나리 보따리
목소리 소쿠리
유리
항아리"""
print(a.findall(d))
--------------------------------------------------------------------------------------------------------------------------------
['보따리', '소쿠리', '유리', '항아리']

’^’와 ‘$’ 메타 문자와 비슷한 의미로 사용할 수 있는 것이 '\A''\Z' 입니다. ‘\A’와 ‘\Z’는 ‘^’와 ‘$’와 같이 문자열의 처음과 끝을 의미합니다. 그러나 re.MULTILINE을 사용할 경우에도 ‘\A’와 ‘\Z’는 기존과 같이 문자열 전체의 처음과 끝을 의미합니다.

import re
a = re.compile("\A좋은\s\w+", re.MULTILINE)
c = """좋은 기분으로
시작한 하루가 많을수록
좋은 인생으로
언젠가 활짝 꽃필거야
좋은 하루 보내길 바랄게"""
print(a.findall(c))
--------------------------------------------------------------------------------------------------------------------------------
['좋은 기분으로']
import re
a = re.compile("\w+리\Z", re.MULTILINE)
e = """리 리 리자로 끝자는 말은
개나리 보따리
목소리 소쿠리
유리
항아리"""
print(a.findall(e))
--------------------------------------------------------------------------------------------------------------------------------
['항아리']


  • re.VERBOSE 또는 re.X : 정규식을 주석 또는 줄 단위로 구분

아래와 같이 정규식이 상당히 복잡한 경우가 있습니다.

import re
a = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
b = "&#x100000000C942A000C9434000C9434000C943400AA;"
print(a.findall(b))
--------------------------------------------------------------------------------------------------------------------------------
['x100000000C942A000C9434000C9434000C943400AA']

따라서, 각 부분마다 주석을 달아주면서 여러 줄로 표현하기 위해 re.VERBOSE 옵션을 사용합니다. 아래를 보다시피 훨씬 가독성이 좋아진 것을 알 수 있습니다. 참고로 문자열에서 사용된 whitespace는 [ ] 안에 있는 것을 제외하고 컴파일할 때 삭제됩니다.

import re
a = 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.X)
c = "&#x100000000C942A000C9434000C9434000C943400AA;"
print(a.findall(c))
--------------------------------------------------------------------------------------------------------------------------------
['x100000000C942A000C9434000C9434000C943400AA']


다음 포스팅으로 그루핑과 전방 탐색에 대해 설명드리겠습니다!


Reference

  1. 점프 투 파이썬 08-2
  2. 점프 투 파이썬 08-3


DATA_100%_LOGO_LIGHT



댓글남기기