python/파이썬 기본
11. 정규표현식 re module
Abokadoh
2023. 2. 13. 15:33
1. 정규표현식이란 (regular expression)
- 특정한 패턴과 일치하는 문자열을 ‘검색’, ‘치환’, ‘제거’하는 기능을 지원한다.
- 정규표현식의 도움없이 패턴을 찾는 작업(Rule 기반)은 불완전 하거나, 작업의 cost가 높다.
- 이메일 형식을 판별, 전화번호 형식 판별, 숫자로만 이루어진 문자열 등…
- raw string
문자열 앞에 r이 붙으면 해당 문자열이 구성된 그대로 문자열로 반환한다.
# <in>
a = 'abcdef\n' #\n은 newline 명령어임
print(a)
b = r'abcdef\n' #문자열 앞에 r을 붙임으로써 \n을 그대로 문자열로 취급
print(b)
# <out>
abcdef
abcdef\n
2. 정규표현식 기본 패턴
- a, X, 9 등 문자 하나하나의 character들은 정확히 해당 문자와 일치한다.
- e.g) 패턴 test는 test 문자열과 일치한다.
- 대소문자의 경우 기본적으로는 구별하나, 구별하지 않도록 설정도 가능하다.
- 몇몇 문자들에 대해서는 예외가 존재하는데, 이들은 특별한 의미로 사용된다.
- . ^ $ * + ? {} [] \ | ()
- .(마침표) → 어떤 한개의 character와 일치 (newline(엔터) 제외)
어떤 character 든 인식한다는 말인 것 같다. 단, 엔터 제외 - \w → 문자 character와 일치 [a-zZ-Z0-9]
\w는 특수문자는 취급하지 않는 것으로 보인다. 특수문자 취급은 위에 마침표(.) - \s → 공백문자와 일치
- \t, \n, \r → tab, newline, return
- \d → 숫자 character와 일치 [0,9]
- ^ → 시작, $ → 끝 각각 문자열의 시작과 끝을 의미한다.
- \가 붙으면 스폐셜한 의미가 없어짐, 예를들어 \.는 .자체를 의미 \\는 \를 의미
- 자세한 내용은 링크
re - Regular expression operations
re — Regular expression operations
Source code: Lib/re/ This module provides regular expression matching operations similar to those found in Perl. Both patterns and strings to be searched can be Unicode strings ( str) as well as 8-...
docs.python.org
3. re.search()
- 첫번째로 패턴을 찾으면 match 객체를 반환
- 패턴을 찾지 못하면 None을 반환
# <in>
import re
m = re.search(r'abc', '123abcdef')
n = re.search(r'abc', '123abdef')
print(m)
print(n)
type(m)
type(n)
# <out>
<re.Match object; span=(3, 6), match='abc'>
None
re.Match
NoneType
# <in>
m = re.search(r'/d/d/d/w', '112abcdef119') #숫자숫자숫자문자
# 첫번째로 패턴을 찾으면 match객체를 반환 112a
m
n = re.search(r'..\w\w', '@#$%ABCDabcd')
# ..은 any character, \w은 any 문자
print(m)
print(n)
# <out>
None
<re.Match object; span=(2, 6), match='$%AB'>
4. metacharacters / [ ]로 문자 범위 나타내기
[ ]로 문자들의 범위를 나타낼 수 있다.
- [ ] 내부의 메타 캐릭터는 캐릭터 자체를 나타냄
- e.g)
- [abck] : a or b or c or k
- [abc.^] : aor b or c or . or ^
- [a-d] : -와 함께 사용되면 해당 문자 사이의 범위에 속하는 문자 중 하나
- [0-9] : 모든 숫자
- [a-z] : 모든 소문자
- [A-Z] : 모든 대문자
- [a-zA-Z0-9] : 모든 알파벳 문자 및 숫자
- [^0-9] ^가 맨 앞에 사용되는 경우 해당 문자 패턴이 아닌 것과 매칭한다.
# <in>
m = re.search(r'[cbm]at','aat') #c or b or m
m # None return
n = re.search(r'[cbm]at','cat')
n # cat return
m = re.search(r'[0-4]haha','7haha')
m # None [0-4]엔 7이 없으므로
n = re.search(r'[abc.^]aron','daron')
n # None
m = re.search(r'[abc.^]aron','^aron')
m
5. \d, \D, \s, \S, \w, \W, \., \\ 사용하기
- 다른 문자와 함께 사용되어 특수한 의미를 지닌다.
- \d : 숫자를 [0-9]와 동일
- \D : 숫자가 아닌 문자 [^0-9]와 동일
- \s : 공백 문자(띄어쓰기, 탭, 엔터 등)
- \S : 공백이 아닌 문자
- \w : 알파벳대소문자, 숫자 [0-9a-zA-Z]와 동일
- \W : non alpha-numeric 문자 [^0-9a-zA-A]와 동일
- 메타 캐릭터가 캐릭터 자체를 표현하도록 할 경우 사용
- \. , \\
# <in>
m = re.search(r'\Sand','apple and banana') # \S : 공백이 아닌 문자
m # and 출력안됨 \Sand -> and앞에 공백이 없는 문자열은 match하기 때문
m = re.search(r'\Sand','apple land banana')
m # land를 출력하겠지요?
re.search(r'\.and','.and') # .을 캐릭터 자체로 표현하고 싶을 때 \를 사용
6. 정규표현식에서 . 의 의미
- 모든 문자를 의미한다.
7. 정규표현식 반복패턴 사용
- 패턴 뒤에 위치하는 *, +, ?는 해당 패턴을 반복적으로 존재하는지를 검사한다.
- ‘+’ → 1번 이상의 패턴이 발생
- ‘*’ → 0번이상의 패턴이 발생
- ‘?’ → 0혹은 1번의 패턴이 발생
- 반복을 패턴의 경우 greedy하게 검색한다. 즉 가능한 많은 부분이 매칭되도록 한다.
- e.g) a[bcd]*b 패턴을 abcbdccb에서 검색하는 경우
- ab, abcb, abcbdccb 전부 매칭이 가능하지만 최대한 많은 부분이 매칭된 abcbdccb가 반한된다.
# <in>
re.search(r'a[bcd]*b','abcbdccb')
re.search(r'b\w+a', 'banana')
re.search(r'i+','piigiii')
re.search(r'pi+g','pg')
re.search(r'pi*g','pg')
re.search(r'https?','http://www.naver.com')
8. ^, $ (맨 앞,뒤부터 일치하는 것 검색하기)
- ^ 문자열의 맨 앞부터 일치하는 경우 검색
- $ 문자열의 맨 뒤부터 일치하는 경우 검색
# <in>
re.search(r'b\w+a','cabana')
re.search(r'^b\w+a','cabana')
re.search(r'^b\w+a','babana')
re.search(r'b\w+a$', 'cabana')
re.search(r'b\w+a$', 'cabanap')
9. grouping
- () 을 사용하여 그룹핑
- 매칭 결과를 각 그룹별로 분리 가능
- 패턴 명시 할 때, 각 그룹을 괄호()안에 넣어 분리하여 사용가능
# <in>
m = re.search(r'(\w+)@(.+)'m 'test@gmai.com')
print(m.group(1))
print(m.group(2))
print(m.group(0))
# <out>
test
gmai.com
test@gmai.com
10. {}을 사용하여 반복 횟수 제한하기.
- *, +, ?을 사용하여 반복적인 패턴을 찾는 것이 가능하지만, 반복의 횟수를 제한할 수 없다.
- 패턴뒤에 위치하는 중괄호 {}에 숫자를 명시하면 해당 숫자 만큼의 반복인 경우메나 매칭한다.
- {4} $\Rightarrow$ 4번 반복
- {3,4} $\Rightarrow$ 3~4번 반복
# <in>
re.search('pi{3,5}g','piiiiig')
미니멈 매칭 (non-greedy way)
- 기본적으로 *, +, ?을 사용하면 greedy(맥시멈 매칭)하게 동작한다.
- *?, +?을 이용하여 해당 기능을 구현할 수 있다.
# <in>
re.search(r'<.+>','<html>haha</html>')
re.search(r'<.+?>','<html>haha</html>')
# <out>
<re.Match object; span=(0, 17), match='<html>haha</html>'>
<re.Match object; span=(0, 6), match='<html>'>
{}?를 사용해서 non-greedy하게
- {m,n}의 경우 m번에서 n번 반복하나 greedy하게 동작한다.
- {m,n}?로 사용하면 non-greedy하게 동작한다. 즉, 최소 m번만 매칭하면 만족
# <in>
re.search(r'a{3,5}','aaaaa')
re.search(r'a{3,5}?', 'aaaaa')
# <out>
<re.Match object; span=(0, 5), match='aaaaa'>
<re.Match object; span=(0, 3), match='aaa'>
match 사용법
- search와 유사하나, 주어진 문자열의 시작부터 비교하여 패턴이 있는지 확인한다.
- 시작부터 해당 패턴이 존재하지 않으면 None을 반환
# <in>
re.match(r'\d\d\d', 'my number is 123')
re.match(r'\d\d\d', '123 is my number')
re.search(r'^\d\d\d', '123 is my number')
# <out>
None
<re.Match object; span=(0, 3), match='123'>
<re.Match object; span=(0, 3), match='123'>
findall 사용법
- search가 최초로 매칭되는 패턴만 반환한다면, findall은 매칭되는 전체의 패턴을 반환한다.
- 매칭되는 모든 결과를 리스트 형태로 반환
# <in>
re.findall(r'[\w-]+@[\w.]+', 'test@gmail.com haha test2@gmail.com nice test test')
# <out>
['test@gmail.com', 'test2@gmail.com']
sub 사용법
- 주어진 문자열에서 일치하는 모든 패턴을 replace
- 그 결과를 문자열로 다시 반환함
- 두번째 인자는 특정 문자열이 될 수도 있고, 함수가 될 수도 있음
- count가 0인 경우는 전체를, 1이상이면 해당 숫자만큼 치환 됨
# <in>
re.sub(r'[\w-]+@[\w.]+','love', 'test@gmail.com haha test2@gmail.com nice test test', count = 1)
# <out>
'love haha test2@gmail.com nice test test'
complie 사용법
- 동일한 정규표현식을 매번 다시 쓰기 번거로움을 해결
- complie로 해당표현식을 re.RegexObject 객체로 저장하여 사용가능하다.
# <in>
email_reg = re.compile(r'[\w-]+@[\w.]+')
email_reg.search('test@gmail.com haha good')
email_reg.findall('test@gmail.com haha good haha plus@naver.com')
# <out>
<re.Match object; span=(0, 14), match='test@gmail.com'>
['test@gmail.com', 'plus@naver.com']