-
[정규표현식] re 모듈머신러닝 & 딥러닝 2021. 11. 30. 15:54
정규표현식
- regular expression
- 특정한 패턴과 일치하는 문자열을 '검색', '치환', '제거' 하는 기능을 지원
- 정규표현식의 도움없이 패턴을 찾는 작업(Rule 기반)은 불완전 하거나, 작업의 cost가 높음
- e.g) 이메일 형식 판별, 전화번호 형식 판별, 숫자로만 이루어진 문자열 등
기본 패턴
- a, X, 9 등등 문자 하나하나의 character들은 정확히 해당 문자와 일치
- e.g) 패턴 test는 test 문자열과 일치
- 대소문자의 경우 기본적으로 구별하나, 구별하지 않도록 설정 가능
- 몇몇 문자 들에 대해서는 예외가 존재하는데, 이들은 특별한 의미로 사용 됨
- . ^ $ * + ? { } [ ] \ | ( )
- . (마침표) - 어떤 한개의 character와 일치 (newline(엔터) 제외)
- \w - 문자 character와 일치 [a-zA-Z0-9_]
- \s - 공백문자와 일치
- \t, \n, \r - tab, newline, return
- \d - 숫자 character와 일치 [0-9]
- ^ = 시작, $ = 끝 각각 문자열의 시작과 끝을 의미
- \가 붙으면 스페셜한 의미가 없어짐. 예를들어 \\.는 .자체를 의미 \\\는 \를 의미
- 자세한 내용은 링크 참조 https://docs.python.org/3/library/re.html
re — Regular expression operations — Python 3.10.0 documentation
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-bit strings (bytes). However, Unicode strings and 8-bit strings cannot be mixed:
docs.python.org
Search method
패턴을 찾으면 match 객체를 반환(제일 첫번째로 찾은 값), 찾기 못하면 None 반환
import re m = re.search(r'abc', '123abdef') m
맞는 패턴이 없으므로 아무것도 출력하지 않는다.
m = re.search(r'\d\d\d\w', '112abcdef119') m
<re.Match object; span=(0, 4), match='112a'>
m = re.search(r'..\w\w', '@#$%ABCDabcd') m
<re.Match object; span=(2, 6), match='$%AB'>
[ ] 문자들의 범위를 나타내기 위해 사용
- [] 내부의 메타 캐릭터는 캐릭터 자체를 나타냄
- [abck] : a or b or c or k
- [abc.^] : a or b or c or . or ^
- [a-d] : -와 함께 사용되면 해당 문자 사이의 범위에 속하는 문자 중 하나
- [0-9] : 모든 숫자
- [a-z] : 모든 소문자
- [A-Z] : 모든 대문자
- [a-zA-Z0-9] : 모든 알파벳 문자 및 숫자
- [^0-9] : ^가 맨 앞에 사용 되는 경우 해당 문자 패턴이 아닌 것과 매칭 즉, 이 경우 숫자가 아닌 것.
[cbm]중에 하나가 나오고 + 'at'가 있는 경우
re.search(r'[cbm]at', 'cat') # 결과 <re.Match object; span=(0, 3), match='cat'>
[0부터 4까지] 숫자 + 'haha' 패턴 찾기
re.search(r'[0-4]haha', '0hahah') #결과 <re.Match object; span=(0, 5), match='0haha'>
abc가 아닌 것 + 'aron' 패턴 찾기
re.search(r'[^abc]aron', '0aron') # 결과 <re.Match object; span=(0, 5), match='0aron'>
\ 표현식
1. 다른 문자와 함께 사용되어 특수한 의미를 지님
- \d : 숫자를 [0-9]와 동일
- \D : 숫자가 아닌 문자 [^0-9]와 동일
- \s : 공백 문자(띄어쓰기, 탭, 엔터 등)
- \S : 공백이 아닌 문자
- \w : 알파벳대소문자, 숫자 [0-9a-zA-Z]와 동일
- \W : non alpha-numeric 문자 [^0-9a-zA-Z]와 동일
2. 메타 캐릭터가 캐릭터 자체를 표현하도록 할 경우 사용- \\. , \\\
re.search(r'\Sand', 'apple land banana') # <re.Match object; span=(6, 10), match='land'>
'.'은 모든 문자를 의미한다. 그러므로 '.' 이 자체를 찾을 때는 \를 써줘야 한다.
re.search(r'\.and', '.and') # <re.Match object; span=(0, 4), match='.and'> re.search(r'p.g', 'pig') # <re.Match object; span=(0, 3), match='pig'>
반복패턴
- 패턴 뒤에 위치하는 *, +, ?는 해당 패턴이 반복적으로 존재하는지 검사
- '+' -> 1번 이상의 패턴이 발생
- '*' -> 0번 이상의 패턴이 발생
- '?' -> 0 혹은 1번의 패턴이 발생
- 반복 패턴의 경우 greedy하게 검색 함, 즉 가능한 많은 부분이 매칭되도록 함
- e.g) a[bcd]*b 패턴을 abcbdccb에서 검색하는 경우
- ab, abcb, abcbdccb 전부 가능 하지만 최대한 많은 부분이 매칭된 abcbdccb가 검색된 패턴
- e.g) a[bcd]*b 패턴을 abcbdccb에서 검색하는 경우
(1) a로 시작되고, (2) bcd중에 하나가 0번 이상 반복 되며, (3) b로 끝나는 패턴. (반복 패턴의 경우, 최대한 많은 부분이 매칭된 부분을 보여줌)
re.search(r'a[bcd]*b', 'abcbdccb') # <re.Match object; span=(0, 8), match='abcbdccb'>
(1) b로 시작해서, (2) 어떤 숫자나 영문자가 1번 이상 반복되고, (3) a로 끝나는 것.
re.search(r'b\w+a', 'banana') # <re.Match object; span=(0, 6), match='banana'>
가장 처음에 매칭된 부분을 보여줌.
re.search(r'i+', 'piigiii') <re.Match object; span=(1, 3), match='ii'>
re.search(r'pi+g', 'pg') # 결과 none (i가 한번 이상은 있어야 하므로) re.search(r'pi*g', 'pg') # <re.Match object; span=(0, 2), match='pg'>
^, $
- ^ 문자열의 맨 앞부터 일치하는 경우 검색
- $ 문자열의 맨 뒤부터 일치하는 경우 검색
re.search(r'b\w+a', 'cabana') # <re.Match object; span=(2, 6), match='bana'> re.search(r'^b\w+a', 'cabana') # None re.search(r'^b\w+a', 'babana') # <re.Match object; span=(0, 6), match='babana'> re.search(r'b\w+a$', 'cabana') # <re.Match object; span=(2, 6), match='bana'>
grouping
- ()을 사용하여 그루핑
- 매칭 결과를 각 그룹별로 분리 가능
- 패턴 명시 할 때, 각 그룹을 괄호() 안에 넣어 분리하여 사용
m = re.search(r'(\w+)@(.+)', 'test@gmail.com') print(m.group(1)) print(m.group(2)) print(m.group(0)) # test # gmail.com # test@gmail.com
{}
- *, +, ?을 사용하여 반복적인 패턴을 찾는 것이 가능하나, 반복의 횟수 제한은 불가
- 패턴뒤에 위치하는 중괄호{}에 숫자를 명시하면 해당 숫자 만큼의 반복인 경우에만 매칭
- {4} - 4번 반복
- {3,4} - 3 ~ 4번 반복
re.search('pi{3,5}g', 'piiiiig') # <re.Match object; span=(0, 7), match='piiiiig'>
미니멈 매칭(non-greedy way)
- 기본적으로 *, +, ?를 사용하면 greedy(맥시멈 매칭)하게 동작함
- *?, +?을 이용하여 해당 기능을 구현
re.search(r'<.+>', '<html>haha</html>') # <re.Match object; span=(0, 17), match='<html>haha</html>'> re.search(r'<.+?>', '<html>haha</html>') # <re.Match object; span=(0, 6), match='<html>'>
{}?
- {m,n}의 경우 m번 에서 n번 반복 하나 greedy하게 동작
- {m,n}?로 사용하면 non-greedy하게 동작. 즉, 최소 m번만 매칭하면 만족
re.search(r'a{3,5}', 'aaaaa') # <re.Match object; span=(0, 5), match='aaaaa'> re.search(r'a{3,5}?', 'aaaaa') # <re.Match object; span=(0, 3), match='aaa'>
match
- search와 유사하나, 주어진 문자열의 시작부터 비교하여 패턴이 있는지 확인
- 시작부터 해당 패턴이 존재하지 않다면 None 반환
re.match(r'\d\d\d', 'my number is 123') # none re.match(r'\d\d\d', '123 is my number') # <re.Match object; span=(0, 3), match='123'> re.search(r'^\d\d\d', '123 is my number') # <re.Match object; span=(0, 3), match='123'>
findall
- search가 최초로 매칭되는 패턴만 반환한다면, findall은 매칭되는 전체의 패턴을 반환
- 매칭되는 모든 결과를 리스트 형태로 반환
re.findall(r'[\w-]+@[\w.]+', 'test@gmail.com haha test2@gmail.com nice test test') # ['test@gmail.com', 'test2@gmail.com']
sub
- 주어진 문자열에서 일치하는 모든 패턴을 replace
- 그 결과를 문자열로 다시 반환함
- 두번째 인자는 특정 문자열이 될 수도 있고, 함수가 될 수 도 있음
- count가 0인 경우는 전체를, 1이상이면 해당 숫자만큼 치환 됨
이메일 패턴을 'great' 단어로 대체
re.sub(r'[\w-]+@[\w.]+', 'great', 'test@gmail.com haha test2@gmail.com nice test test', count=1) # 'great haha test2@gmail.com nice test test'
compile
- 동일한 정규표현식을 매번 다시 쓰기 번거로움을 해결
- compile로 해당표현식을 re.RegexObject 객체로 저장하여 사용가능
email_reg = re.compile(r'[\w-]+@[\w.]+') email_reg.search('test@gmail.com haha good') email_reg.findall()
다음 뉴스 기사에서 이메일 주소 가져오기
import requests from bs4 import BeautifulSoup # 위의 두 모듈이 없는 경우에는 pip install requests bs4 실행 import re def get_news_content(url): response = requests.get(url) content = response.text soup = BeautifulSoup(content, 'html5lib') div = soup.find('div', attrs = {'id' : 'harmonyContainer'}) content = '' for paragraph in div.find_all('p'): content += paragraph.get_text() return content news1 = get_news_content('https://news.v.daum.net/v/20211130150537546') print(news1)
email_reg = re.compile(r'[\w-]+@[\w.]+\w+') email_reg.search(news1)
'머신러닝 & 딥러닝' 카테고리의 다른 글
[텍스트] KoNLPy 맥 M1 설치하기 (0) 2021.12.05 [텍스트] 문서 유사도 (0) 2021.12.04 [텍스트] 토픽 모델링 & LDA (0) 2021.11.29 [텍스트] 감성 분석 (Sentiment Analysis) (0) 2021.11.28 [텍스트] 20개의 뉴스 그룹으로 분류하기 (0) 2021.11.28