파이썬 모듈에는 정규 표현식이라는 regular expression모듈이 있다.
우선 메타 문자에 대해 살펴보자.
메타 문자란 원래 그 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자라고 한다.
. ^ & * + ? { } [ ] / | ( )
문자클래스 [ ]
- [ ] 사이의 문자들과의 매치 라는 의미를 갖는다.
예를 들자면 [qwer] 는 문자열 "q","w","e","r" 중 한 개의 문자와 매치를 의미한다고 한다.
- " query " 는 "q"와 매치
- "word" 는 정규식과 일치하는 문자인 "w"가 있으므로 매치
- "man"은 정규식과 일치하는 문자가 없으므로 매치되지 않는다.
[ ] 안의 두 문자 사이에 하이픈(-)를 사용하면 두 문자 사이의 범위를 의미하는데, [a-z]는 a부터 z까지를 의미하고
[0-5]는 012345를 의미한다.
- [a-zA-Z] : 모든 알파벳 문자
- [0-9] : 모든 숫자
별도의 표기법도 존재한다.
\d # 숫자와 매치 = [0-9]
\D # 숫자가 아닌 것과 매치. = [^0-9]
\s # Space(공백)과 매치. = [ \t\n\r\f\v] (뭐 이리 복잡한지)
\S # Sapce(공백)이 아닌 것과 매치 = [^ \t\n\r\f\v]
\w # 문자 + 숫자와 매치 [a-zA-Z0-9]
\W # 문자 + 숫자가 아닌 것과 매치 [^a-zA-Z0-9]
Dot(.) 메타 문자는 줄바꿈 문자인 \n를 제외한 모든 문자와 매치를 의미한다.
a.b
a와 b 사이의 어떤 문자가 들어가도 매치된다는 의미다.
a[.]b
" a + Dot(.)문자 + b"
위의 것과 다른 점이 무엇일까?
바로 문자 클래스 [ ] 안에 Dot(.) 가 들어갔다는 점이다. 즉 위의 a.b는 a0b a8b aGb 뭐든 된다면
아래의 a[.]b는 말 그대로 "문자"클래스이기 때문에 a0b와 같은 숫자가 들어오면 매치될 수 없다. aGb는 가능.
반복 (*)
반복 정규식이다.
ca*t
* 바로 앞 문자인 a가 0부터 무한대로 반복될 수 있다는 의미라고 한다.
0부터라는 것은 a가 없을 수도 있다는 의미이다.
ct, cat, caaaaaaaaat 모두 Match 된다는 의미이다.
반복 (+)
ca+t
*와 비슷하나 1부터 시작한다. 즉 ct는 매치되지 않는다.
반복 ({m,n}), ?)
m부터 n까지 매치할 수 있고, m또는 n을 생략할 수도 있다. 생략은 무한, 또는 0을 의미한다.
ca{2}t # a는 반드시 2번 반복 = caat - 매치, 그 외에는 매치되지 않음
ca{2,5}t # a는 2~5회 반복. caa~ aaaaat - 매치, 그 외에는 매치되지 않음. ex)cat x
ca{,3}t # a는 0~3회 반복
ca{4,}t # a는 4~무한회 반복
ca?t # a가 있어도 되고 없어도 된다. 반복의 의미는 아니다. {0,1}과 같은 의미
파이썬에서는 re 모듈을 제공한다.
import re
p = re.compile('ab*')
re.compile을 사용하여 정규 표현식을 컴파일한다. re.compile의 결과를 돌려주는 객체 p(컴파일된 패턴 객체)를 이용하여
다음 작업을 수행할 수 있다.
match() : 문자열의 처음부터 정규식과 매치되는지 조사
search() : 문자열 전체를 검색하여 정규식과 매치되는지 조사
findall() : 정규식과 매치되는 모든 문자열을 리스트로 돌려준다
finditer() : 정규식과 매치되는 모든 문자열을 반복 가능한 객체로 돌려준다
아래는 match() 메소드이다.
import re
p = re.compile(['a-z']+)
m = p.match("jinseong")
print(m)
<re.Match object; span(0,8), match = 'jinseong'> #"jinseong" 문자열은 [a-z]+ 정규식에 부합된다.
# 만약 j 대신 J를 사용했다면 None이 반환될 것이다.
match, search는 정규식과 매치될 떄는 match 객체를 돌려주고, 매치되지 않을 때는 None을 돌려준다.
그래서 보통
if m :
~~~~~~~~~~~~~
else :
~~~~~~~~~~~~~
이런 식으로 많이 쓴다고들 한다.
다음은 search이다.
p = re.compile(['a-z']+)
m = p.search("Jinseong")
print(m)
<re.Match object; span=(1, 8), match='inseong'> # J는 정규식에 포함되지 않으므로 이런 결과가 나온다.
findall
p = re.compile('[a-z]+')
result = p.findall("Cola is 1.8L")
print(result) #['ola', 'is']
"Cola" ,"is", "1.8L" 각각에 정규식과 매치해서 리스트로 돌려준다.
finditer
p = re.compile('[a-z]+')
result = p.finditer("where is my glasses?")
print(result) # <callable_iterator object at 0x000002BCEC5E8400>
for r in result :
print(r)
#<re.Match object; span=(0, 5), match='where'>
#<re.Match object; span=(6, 8), match='is'>
#<re.Match object; span=(9, 11), match='my'>
#<re.Match object; span=(12, 19), match='glasses'>
findall과 동일하지만 반복 가능한 객체를 돌려준다.
match 객체의 메서드는
group(), start(), end(), span()이 있고
각각 매치된 문자열,
매치된 문자열의 시작 위치,
매치된 문자열의 끝 위치,
매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다.
백슬래시 문제
어떤 파일에 들어있는 \section 문자열을 찾기 위한 정규식을 만든다고 가정할 때 백 슬래시를 두 번 해주어 이스케이프 처리를 해야함.
ex)
p = re.compile('\\section') # 하지만 파이썬 정규식 엔진에는 파이썬 문자열 리터럴 규칙에 따라 \\가 \로 변경됨.
p = re.compile('\\\\section') # 백슬래시를 4개 주어야 원하는 값을 얻을 수 있음.
p = re.compile(r'\\section') # 정규식 문자열 앞에 r 문자를 삽입하면 이 정규식이 Row String 규칙에 의하여 \1개가 \2개의 효과를 가짐
# \를 사용하지 않는다면 r의 유무와 관계없이 동일한 정규식이 될 것이다.
메타문자
| 메타 문자는 or과 동일한 의미로 사용됨.
p = re.compile('A|B')
^메타 문자는 문자열의 맨 처음과 일치함을 의미한다.
print(re.search('^Life', 'Life is too short')) # <re.Match object; span(0, 4), match = 'Life'>
$ 메타 문자는 ^ 메타 문자와 반대의 경우이다. $는 문자열 끝과 매치함을 의미한다.
print(re.search('short$', 'Life is too short')) # <re.Match object; span(12, 17), match = 'short'>
그 외에 \A , \Z, \b 등이 있고 그 외에도 많은 것들이 있는데, 너무 길어지니 다음 접할 기회가 되면 정리해야겠다.
sub('패턴', '변경문자열', '문자열', 변경횟수) : 패턴과 일치되는 부분을 다른 문자로 변경
#파이썬 #코테 #코딩테스트 #프로그래머스 #programmers #정규표현식 #re #regularexpression
'개발공부 > Python 문법' 카테고리의 다른 글
[Python] rjust, ljust() (0) | 2022.01.23 |
---|---|
[Python] isdigit() (0) | 2022.01.20 |
[Python] int(), 진법변환 (0) | 2022.01.18 |
[Python] set() 함수 (0) | 2022.01.18 |
[Python] 문자열 split(), join() (0) | 2022.01.17 |