정규표현식
정규표현식
문자 클래스 []
[0-9] 또는 [a-zA-Z] 등은 무척 자주 사용하는 정규 표현식이다.
\d
- 숫자와 매치, [0-9]와 동일한 표현식이다.\D
- 숫자가 아닌 것과 매치,[^0-9]
와 동일한 표현식이다.\s
- whitespace 문자와 매치,[ \t\n\r\f\v]
와 동일한 표현식이다. 맨 앞의 빈 칸은 공백문자(space)를 의미한다.\S
- whitespace 문자가 아닌 것과 매치,[^ \t\n\r\f\v]
와 동일한 표현식이다.\w
- 문자+숫자(alphanumeric)와 매치,[a-zA-Z0-9_]
와 동일한 표현식이다.\W
- 문자+숫자(alphanumeric)가 아닌 문자와 매치,[^a-zA-Z0-9_]
와 동일한 표현식이다.
대문자로 사용된 것은 소문자의 반대임을 추측할 수 있다.
Dot(.)
정규 표현식의 Dot(.) 메타 문자는 줄바꿈 문자인 \n
을 제외한 모든 문자와 매치됨을 의미한다.
a.b : "a + 모든문자 + b"
# abc (x)
a[.]b : "a + . + b"
반복 (*)
ca*t : ct, cat, caaaaaaaaat
# a가 0번 이상 반복
반복 (+)
ca+t : cat, caaat # ct(x)
# a가 1번 이상 반복
반복 ({m,n}, ?)
ca{2}t : caat
# a가 2번 반복
ca{2,5}t : caat, caaaaat
# a가 2~5번 반복
ab?c : ac, abc
# b가 있어도되고 없어도 된다. 단, 반복은 아니다. ab{0,1}c 와 같은 의미
파이썬 re 모듈
>>> import re
>>> p = re.compile('[a-z]+') # 정규표현식을 컴파일한다.
정규식을 이용한 문자열 검색
1. match
문자열의 처음부터 정규식과 매치되는지 조사
p = re.complie('[a-z]+')
>>> m = p.match("python")
>>> print(m)
<_sre.SRE_Match object at 0x01F3F9F8>
# 매치되므로 돌려줌
>>> m = p.match("3 python")
>>> print(m)
None
# 매치되지 않음
p = re.compile(정규표현식)
m = p.match( 'string goes here' )
if m:
print('Match found: ', m.group())
else:
print('No match')
# 매치되면 돌려주고 아니면 No match 출력
2. search
문자열 처음부터 검색하면서 일치하는 부분을 리턴해줌
>>> m = p.search("python")
>>> print(m)
<_sre.SRE_Match object at 0x01F3FA68>
# 매치되므로 돌려줌
>>> m = p.search("3 python")
>>> print(m)
<_sre.SRE_Match object at 0x01F3FA30>
# 일치하는 부분만 리턴해줌
3. findall
매치되는 문자열들을 리스트로 리턴해줌
>>> result = p.findall("life is too short")
>>> print(result)
['life', 'is', 'too', 'short']
4. finditer
findall과 동일하지만 반복 가능한 객체(iterator object)로 돌려준다.
>>> 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>
match 객체의 메서드
method | 목적 |
---|---|
group() | 매치된 문자열을 돌려준다. |
start() | 매치된 문자열의 시작 위치를 돌려준다. |
end() | 매치된 문자열의 끝 위치를 돌려준다. |
span() | 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다. |
>>> m = p.match("python")
>>> m.group()
'python'
>>> m.start()
0
>>> m.end()
6
>>> m.span()
(0, 6)
>>> m = p.search("3 python")
>>> m.group()
'python'
>>> m.start()
2
>>> m.end()
8
>>> m.span()
(2, 8)
컴파일 옵션
DOTALL, S
re.DOTALL
또는re.S
.
은 줄바꿈 문자\n
를 제외한 모든 것과 매치된다. 컴파일 할 때re.DOTALL
또는re.S
옵션을 넣어주면\n
까지 매치되도록 할 수 있다.
>>> p = re.compile('a.b', re.DOTALL)
# .는 \n을 포함하지 않기 때문에 원래 None이지만, re.DOTALL 또는 re.S를 사용하면 .에 \n도 포함됌
>>> m = p.match('a\nb')
>>> print(m)
<_sre.SRE_Match object at 0x01FCF3D8>
#### IGNORECASE, I
re.IGNORECASE
또는re.I
- 대소문자 구별 없이 매치
>>> 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>
#### MULTILINE, M
re.MULTILINE
또는re.M
^
메타문자를 문자열 전체의 처음이 아니라, 각 라인의 처음으로 인식시킨다. 즉re.MULTILINE
옵션은^
,$
메타 문자를 문자열의 각 줄마다 적용해 주는 것이다.
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
- 해당 옵션을 주면 좀 더 가독성 좋게 정규표현식을 작성할 수 있게 된다. 아래의 두 표현식은 동일하게 작동한다.
p = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
p = 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) # re.VERBOSE 옵션 추가
re.VERBOSE
옵션을 추가하면 정규표현식에 컴파일시 자동으로 제거되는 공백과 코멘트를 추가할 수 있게된다.
(단, []
안에 입력된 공백문자 제외)
Python 정규표현식의 \
문제
Python에서 정규표현식에 \
을 사용할 때 아래와 같은 문제가 발생할 수 있다.
text = '\section'
result = re.match('\\section', text)
print(result)
None
\s
는 공백문자를 뜻하는 메타문자로 인식되기 때문에 \section
이라는 문자열을 찾으려면 위해 이스케이프 코드 \\
를 사용한 \\section
를 정규표현식에 입력해야한다.
그러나 Python 정규식 엔진에서 리터럴 규칙에 의해 \\
가 \
로 해석되어 전달된다.
따라서 \\
를 문자 그대로 넘겨주어야하는데 이를 위해서는 \\\\
로 입력해야한다.
text = '\section'
result = re.match('\\\\section', text)
print(result)
<_sre.SRE_Match object; span=(0, 8), match='\\section'>
가독성이 심각하게 저하되는데 이를 방지하기 위해 다음과 같이 작성한다.
text = '\section'
result = re.match(r'\\section', text) # raw string을 뜻하는 r을 앞에 붙여준다.
print(result)
<_sre.SRE_Match object; span=(0, 8), match='\\section'>
정규표현식 앞에 r
은 항상 붙여주는 것이 권장된다.
댓글남기기