이해하기 쉽고, 장황하지 않은 자료를 기반으로 강의를 진행합니다.
잔재미코딩 소식 공유
좀더 제약없이, IT 컨텐츠를 공유하고자, 자체 온라인 사이트와, 다음 두 채널도 오픈하였습니다
응원해주시면, 곧 좋은 컨텐츠를 만들어서 공유하겠습니다
●  잔재미코딩 뉴스레터 오픈 [구독해보기]
●  잔재미코딩 유투브 오픈 [구독해보기]

4. 정규표현식

프로그래밍 연습(생각만 해보기)
다음 코드를 실행해보고, 이름 정보를 통해 남자인지, 여자인지, 기타인지(남녀 구별 불가)를 확인할 수 있는 방법 생각해보기

import openpyxl

# 엑셀파일 열기
work_book = openpyxl.load_workbook('data/train.xlsx')

# 현재 Active Sheet 얻기
work_sheet = work_book.active

# work_sheet.rows는 해당 쉬트의 모든 행을 객체로 가지고 있음
for each_row in work_sheet.rows:
    print (each_row[3].value)

work_book.close()

세 라인의 코드를 추가하면 이름의 특징을 추출할 수 있음

import re
regex = re.compile('[A-Za-z]+\.')
print (regex.findall(each_row[3].value))
In [ ]:
import openpyxl
import re

regex = re.compile(' [A-Za-z]+\.')
# 엑셀파일 열기
work_book = openpyxl.load_workbook('data/train.xlsx')

# 현재 Active Sheet 얻기
work_sheet = work_book.active

# work_sheet.rows는 해당 쉬트의 모든 행을 객체로 가지고 있음
for each_row in work_sheet.rows:
    print (each_row[3].value)
    print (regex.search(each_row[3].value))
    print (regex.findall(each_row[3].value))    

work_book.close()

'[A-Za-z]+.' --> regular expression 이라고 함

  • 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식
정규 표현식 축약 표현 사용 예
[0-9] \d 숫자를 찾음
[^0-9] \D 숫자가 아닌 것을 찾음(텍스트, 특수 문자, white space(스페이스, 탭, 엔터 등등)를 찾을 때)
[ \t\n\r\f\v] \s white space(스페이스, 탭, 엔터 등등) 문자인 것을 찾음
[^ \t\n\r\f\v] \S white space(스페이스, 탭, 엔터 등등) 문자가 아닌 것을 찾음(텍스트, 특수 문자, 숫자를 찾을 때)
[A-Za-z0-9] \w 문자, 숫자를 찾음
[^A-Za-z0-9] \W 문자, 숫자가 아닌 것을 찾음

예: 문자, 숫자가 아닌 데이터를 찾아서, '' 로 대체해라(삭제해라)

In [ ]:
import re
string = "(Dave)"
re.sub('[^A-Za-z0-9]', '', string)    # 문자, 숫자가 아닌 데이터를 찾아서, '' 로 대체해라(삭제해라)

위 정규 표현식은 일정한 규칙을 가지고 작성됨, 필요한 패턴은 직접 만들 수도 있음

4.1. Dot .

  • Dot . 메타 문자는 줄바꿈 문자인 \n를 제외한 모든 문자(한 개)를 의미함
  • 예: D.A 는 D + 모든 문자(한 개) + A 를 의미
    • DAA, DvA, D1A

정규 표현식 라이브러리 임포트하기

In [ ]:
import re

정규 표현식 패턴 만들기

In [ ]:
pattern = re.compile('D.A')

패턴에 매칭되는지 여부 확인하기 (실습)

In [ ]:
pattern.search("DAA")
In [ ]:
pattern.search("D1A")
In [ ]:
pattern.search("D00A")
In [ ]:
pattern.search("DA")
In [ ]:
pattern.search("d0A")
In [ ]:
pattern.search("d0A D1A 0111")

정말 Dot . 이 들어간 패턴을 찾으려면?

\. 으로 표시하거나, [.] 으로 표시하면 됨
In [ ]:
pattern = re.compile('D\.A')
In [ ]:
pattern.search("D.A")
In [ ]:
pattern.search("DDA")
In [ ]:
pattern = re.compile('D[.]A')
In [ ]:
pattern.search("D.A")

찾고 바꾸기 (특정 패턴이 매칭되는 것을 찾아서, 다른 문자열로 바꾸기)

In [ ]:
string = "(Dave)"
In [ ]:
# re.sub(패턴, 바꿀데이터, 원본데이터)
re.sub('[^A-Za-z0-9]', '', string)    # 문자, 숫자가 아닌 데이터를 찾아서, '' 로 대체해라(삭제해라)
In [ ]:
# re.sub(패턴, 바꿀데이터, 원본데이터)
re.sub('[^A-Za-z0-9]', '--------------', string)    # 문자, 숫자가 아닌 데이터를 찾아서, '' 로 대체해라(삭제해라)
In [ ]:
string = "-----(Dave)!@   "
In [ ]:
re.sub('[^A-Za-z0-9]', '', string)    # 문자, 숫자가 아닌 데이터를 찾아서, '' 로 대체해라(삭제해라)
In [ ]:
string = "1-----(Dave)!@   1"
re.sub('[^A-Za-z0-9]', '', string)    # 문자, 숫자가 아닌 데이터를 찾아서, '' 로 대체해라(삭제해라)

4.2. 반복 ? , * , +

  • ? 는 앞 문자가 0번 또는 1번 표시되는 패턴 (없어도 되고, 한번 있어도 되는 패턴)
  • * 는 앞 문자가 0번 또는 그 이상 반복되는 패턴
  • + 는 앞 문자가 1번 또는 그 이상 반복되는 패턴

? 사용 예

In [ ]:
pattern = re.compile('D?A')     # 앞에 문자 D가 없거나, 여러번 반복되고 마지막이 A 인 문자열
In [ ]:
pattern.search("A")
In [ ]:
pattern.search("DA")
In [ ]:
pattern.search("DDA")
In [ ]:
 

* 사용 예

In [ ]:
pattern = re.compile('D*A')     # 앞에 문자 D가 없거나, 여러번 반복되고 마지막이 A 인 문자열
In [ ]:
pattern.search("A")
In [ ]:
pattern.search("DA")
In [ ]:
pattern.search("DDDDDDDDDDDDDDDDDDDDDDDDDDDDA")
In [ ]:
pattern = re.compile('AD*A')     # 앞에 문자 D가 없거나, 여러번 반복되고 마지막이 A 인 문자열
In [ ]:
pattern.search("ADA")
In [ ]:
pattern.search("ADDDDDDDDDDDDDDDDDDA")
In [ ]:
 

+ 사용 예

In [ ]:
pattern = re.compile('D+A')
In [ ]:
pattern.search("A")
In [ ]:
pattern.search("DA")
In [ ]:
pattern.search("DDDDDDDDDDDDDDDDDDDDDDDDDDDDA")

또다른 반복 표현: {n}, {m,n}

  • {n} : 앞 문자가 n 번 반복되는 패턴
  • {m, n} : 앞 문자가 m 번 반복되는 패턴부터 n 번 반복되는 패턴까지

{n} 사용 예

In [ ]:
pattern = re.compile('AD{2}A')
In [ ]:
pattern.search("ADA")
In [ ]:
pattern.search("ADDA")
In [ ]:
pattern.search("ADDDA")

{m,n} 사용 예

In [ ]:
pattern = re.compile('AD{2,6}A')    # {m,n} 은 붙여 써야 함 {m, n} 으로 쓰면 안됨(특이함)
In [ ]:
pattern.search("ADDA")
In [ ]:
pattern.search("ADDDA")
In [ ]:
pattern.search("ADDDDDDA")

4.3. [ ] 괄호 : 괄호 안에 들어가는 문자가 들어 있는 패턴

  • 예: [abc] 는 a, b, c 중 하나가 들어 있는 패턴을 말함
In [ ]:
pattern = re.compile('[abcdefgABCDEFG]')    
In [ ]:
pattern.search("a1234")
In [ ]:
pattern.search("z1234")  

하이픈(-)을 이용하면 알파벳 전체를 나타낼 수 있음

  • 예: [a-c] 는 a, b, c 중 하나가 들어 있는 패턴을 말함
In [ ]:
pattern = re.compile('[a-z]')    
In [ ]:
pattern.search("k1234")  
In [ ]:
pattern.search("Z1234")  

[a-zA-Z] 으로 표기하면 대소문자를 모두 포함해서 알파벳 전체를 나타낼 수 있음

In [ ]:
pattern = re.compile('[a-zA-Z]') 
In [ ]:
pattern.search("Z1234")  

[a-zA-Z0-9] 로 표기하면 대소문자를 모두 포함해서 알파벳 전체와 함께 숫자 전체도 나타낼 수 있음

In [ ]:
pattern = re.compile('[a-zA-Z0-9]') 
In [ ]:
pattern.search("1234---") 
In [ ]:
pattern.search("---------------!@#!@$!$%#%%%#%%@$!$!---") 

[ ] 괄호 안에서 [ 바로 뒤에 ^ 을 쓰면 그 뒤에 오는 문자가 아닌 패턴을 찾음

  • 문자를 결국 알파벳, 숫자, 특수문자, whitespace(스페이스, 탭, 엔터등) 로 분류할 수 있으므로
  • [^ \t\n\r\f\v] 는 이중에서 whitespace 가 아닌 알파벳, 숫자, 특수문자를 지칭함
In [ ]:
pattern = re.compile('[^a-zA-Z0-9]') 
In [ ]:
pattern.search("---------------!@#!@$!$%#%%%#%%@$!$!---") 
In [ ]:
 
In [ ]:
pattern = re.compile('[^ \t\n\r\f\v]') 
In [ ]:
pattern.search("-") 
In [ ]:
pattern.search(" ")

그러면 한글만? --> [가-힣]

In [ ]:
pattern = re.compile('[가-힣]') 
In [ ]:
pattern.search("안") 

4.4. 조합해서 써보자

In [ ]:
import re
pattern = re.compile('[a-zA-Z]+')
matched = pattern.search("Dave")
print(matched)

4.5. 정규 표현식 라이브러리 함수 사용법

match 와 search 함수

  • match : 문자열 처음부터 정규식과 매칭되는 패턴을 찾아서 리턴
  • search : 문자열 전체를 검색해서 정규식과 매칭되는 패턴을 찾아서 리턴
In [ ]:
import re
pattern = re.compile('[a-z]+')
In [ ]:
matched = pattern.match('Dave')
In [ ]:
searched = pattern.search("Dave")
In [ ]:
print (matched)
In [ ]:
print (searched)

findall 함수: 정규표현식과 매칭되는 모든 문자열을 리스트 객체로 리턴함

In [ ]:
import re
pattern = re.compile('[a-z]+')
findalled = pattern.findall('Game of Life in Python')
In [ ]:
print (findalled)
In [ ]:
pattern2 = re.compile('[A-Za-z]+')
In [ ]:
findalled2 = pattern2.findall('Game of Life in Python')
In [ ]:
print (findalled2)

finditer 함수: 정규표현식과 매칭되는 모든 문자열을 iterator 객체로 리턴함

In [ ]:
import re
pattern2 = re.compile('[A-Za-z]+')
finded_data = pattern2.finditer('Game of Life in Python')
In [ ]:
for finded in finded_data:
    print (finded)   # 각각은 match 객체임

match 객체 주요 함수

  • group() : 매칭된 문자열 리턴
  • start() : 매칭된 문자열의 시작 위치 리턴
  • end() : 매칭된 문자열 끝 위치 리턴
  • span() : 매칭된 문자열의 (시작, 끝) 위치를 튜플로 리턴
In [ ]:
import re
pattern2 = re.compile('[A-Za-z]+')
finded_data = pattern2.finditer('Game of Life in Python')
In [ ]:
for finded in finded_data:
    print (finded.group())
    print (finded.start())
    print (finded.end())
    print (finded.span())    

split 함수: 찾은 정규표현식 패턴 문자열을 기준으로 문자열을 분리

In [ ]:
import re
pattern2 = re.compile(':')
splited = pattern2.split('python:java')
In [ ]:
print (splited)
프로그래밍 연습
' VS ' 로 문자열 앞뒤를 분리해보기
In [ ]:
import re
pattern2 = re.compile(' [A-Z]{2} ')
splited = pattern2.split('python VS java')
print (splited)

sub 함수: 찾은 정규표현식 패턴 문자열을 다른 문자열로 변경

In [ ]:
import re
pattern2 = re.compile('-')
subed = pattern2.sub('*', '801210-1011323')  # sub(바꿀문자열, 본래문자열)
In [ ]:
print (subed)
In [ ]:
subed = re.sub('-', '*', '801210-1011323')  # sub(정규표현식, 바꿀문자열, 본래문자열)
In [ ]:
print (subed)
In [ ]:
 
In [ ]:
801210-*******

도전 과제
주민번호 뒷자리를 * 로 바꿔서 가려보기
re.sub('-------', '------', each_row[1].value) <--- 정규표현식, 바꿀문자열 을 넣어봅니다.

import openpyxl
work_book = openpyxl.load_workbook('data/data_kr.xlsx')
work_sheet = work_book.active
for each_row in work_sheet.rows:
    print(re.sub('-------', '------', each_row[1].value))

work_book.close()
In [ ]:
import openpyxl
work_book = openpyxl.load_workbook('data/data_kr.xlsx')
work_sheet = work_book.active
for each_row in work_sheet.rows:
    print(re.sub('-[0-9]{7}', '-*******', each_row[1].value))

work_book.close()