프로그래머스 문제 중 매칭 점수 (42893)을 풀면서 내가 알고 있는 무기인 split매서드와 strip매서드로 최대한 활용해보았지만 TC 9번을 해결할 수가 없어서 포기하고 다른 사람들의 풀이를 찾아보았다.
파이썬을 이용해서 푼 사람들 대부분이 re라이브러리를 불러와서 정규화라는 것을 활용하는 것을 확인할 수 있었다. TC 9번과 11번의 어려운 예외를 정규화라는 것으로 뚝딱 해결하는 것을 보고, 이건 좀 공부해놓으면 좋겠는데?라는 생각이 들어 공부를 해보았다.
1. 정규표현식(Regular expression)이 무엇일까?
정규 표현식(REs, regexres, regex pattern)이란 파이썬 내부의 re모듈을 통해 사용할 수 있는, 전문화된 프로그래밍 언어이다. 정규표현식은 문자열 집합에 대한 규칙을 지정하고, 문자열들이 내가 지정한 규칙과 일치하는지 또는, 문자열이 내 패턴과 일치하는 부분이 있는지 확인할 수 있게 해 준다. 추가로, 이 점들을 활용하여 문자열을 수정하거나 내가 원하는 기준으로 분할까지 할 수 있게 해 준다.
2. 정규식은 어떻게 사용할까?
2-1 정규식 컴파일 하기
정규식은 패턴 객체로 컴파일되는데, 패턴 일치를 검색하거나 문자열 취항을 수행하는 등의 다양한 메서드를 가지고 있다.
import re
p = re.compile('ab*')
p = re.compile('ab*', re.IGNORECASE)
위와 같이 컴파일을 하면, 정규식은 문자열로 re.compile()에 제공된다. re.compile의 인자로는 필수 인자인 패턴과 특수 기능과 문법 변형을 가능하게 하는 선택 인자 flags가 존재한다. (flags에 대해서는 후에 다루어 보자!)
2-2 일치 수행하기
정규식을 컴파일한 객체가 있다면, 다양한 메서드를 활용하여 우리가 원하는 작업을 할 수 있다. 다양한 매서드는 re설명서를 통해서 확인 가능하다. 대표적인 매서드로는 match(), search(), findall()가 있다.
match()를 이용하면 문자열의 시작 부분에서 정규식(RE)와 일치하는 부분이 있다면 객체를 반환한다. 그리고 우리는 그 객체의 메서드를 이용하여 우리가 원하는 정보를 찾을 수 있다
p = re.compile('abc')
m = p.match('abcde')
# <re.Match object; span=(0, 3), match='abc'>
print(m.group()) # 패턴과 일치하는 문자열 반환
print(m.start()) # 패턴과 일치하는 문자열의 시작점 반환
print(m.end()) # 패턴의 끝 위치를 반환
print(m.span()) # 패턴의 시작과 끝을 튜플로 반환
match()는 시작부분에서 찾기 때문에 위와 같은 상황에서 m = p.match('efabc')를 한다면 찾지 못하고 Null 값을 반환한다.
search()는 문자열을 훑으면서 자신이 원하는 패턴을 찾고, 찾는다면 match와 같은 객체를 반환한다.
p = re.compile('abc')
m = p.search('deabc')
print(m.group()) # abc
print(m.start()) # 2
print(m.end()) # 5
print(m.span()) # (2,5)
match()는 항상 시작점이 0이지만, search()는 문자열 전체를 훑기 때문에 시작점이 0이 아닐 수도 있다는 차이점이 있다.
findall()은 컴파일된 매서드에 일치하는 문자를 리스트의 형태로 반환한다.
p = re.compile(r'\d+')
a = p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-leaping')
# ['12', '11', '10']
위의 'r'/d+'는 표현식을 나타내는 메타 문자로 모든 숫자를 찾는다는 의미이고 [0-9]와 동일한 의미를 가진다. re라이브러리를 통한 정규표현식을 잘 활용하고 싶다면 정규표현식을 어떻게 사용하는지도 중요하지만, 공식문서의 메타 문자를 보면서 자신이 활용활 수 있는 것이 어떤 것이 있는지 찾아가면서 활용해 보는 것이 중요한 것 같다.
3. 예시를 활용하며 메타문자 공부하기
위에서 설명한 것 처럼, 결국 정규식을 활용하기 위해서 가장 중요한 것은 메타 문자를 활용하여 나의 패턴을 어떻게 표현하는 가에 달린 것 같다. 하지만 파이썬 공식문서에 나오는 메타 문자만 해도 엄청 많고, 하나하나 이해하기도 어려워서 프로그래머스를 풀면서 내가 활용한 메타 문자를 정리해 보았다.
- ". "
- 개행문자를 제외한 모든 문자와 일치하며, 개행 문자와도 일치하게 만드는 flag(re.DOTALL)이 있다. 말 그대로 모든 문자와 일치시키기 위해 사용한다.
- 아래 예시를 보면 내가 원하는 문자의 *을 .으로 바꿔서 컴파일했다. 사실 "|w"를 사용해도 됐지만 후의 문자열 길이 비교를 위해 길이가 변하지 않는. 을 사용했다
for char in ban_id:
key += '.' if char == '*' else char # * 을 .으로 바꿔서 패턴을 컴파일함
exp = re.compile(key)
for id in user_id:
if len(ban_id) == len(id) and exp.match(id):
candiates[i].append(id)
- " |W "
- 모든 비 영숫자와 일치한다
- 비슷한 메타문자로 "."과 "|w"이 존재한다 "|w"는 모든 영숫자와 일치함을 의미한다
- "[ ]"
- 문자집합을 나타내는 데 사용한다.
- 문자를 개별적으로 나열하는데 사용될 수 있으며, '-'를 이용하여 문자의 범위를 나타내는 것도 가능하다
- 예를들어 [0-9]이면 모든 숫자를. [a-z]이면 모든 소문자를 찾을 수 있다.
- 집합의 첫글자가 '^'이면 부정형으로 집합의 속하지 않는 모든 문자를 찾을 수 있다.
- and는 쉼표로 구분하지 않고 연달아 사용된다 즉, 0과4사이이거나 c인 규칙을 찾고 싶다면 [0-4c]이런식으로 찾을 수 있다.
exp = re.compile('[a-zA-Z][a-zA-Z]')
# 두 글자가 모두 알파벳인 단어를 찾을 때 사용할 수 있다
The Backslash Plague
참고 문서 :
파이썬 정규 문서 : https://docs.python.org/3/howto/regex.html
'개발' 카테고리의 다른 글
[Python] heaqp 라이브러리를 이용한 우선순위 큐 (0) | 2022.06.02 |
---|---|
[SSAFY] 1학기 최종 프로젝트 : 영화 추천 사이트 (0) | 2022.05.28 |
[Python] collections.Counter : 딕셔너리 서브 클래스 (0) | 2022.05.15 |
[Programmers] 2021 KAKAO BLIND RECRUITMENT : 합승 택시 요금 :Python (0) | 2022.05.06 |
[PROGRAMMERS] 월간 코드 챌린지 시즌 1 : 쿼드압축 후 개수 세기 Python (0) | 2022.05.02 |