[PYTHON] 파이썬 정규표현식

지수·2023년 4월 2일
0

플레이데이터

목록 보기
17/50
post-thumbnail

💬 22일차 후기: 파이썬 수업은 이론 학습 대신 프로젝트 진행으로 이루어지고 있기 때문에 TIL 정리가 뜸했다. (TIL보다 더 많은 코드를 작성하고 commit을 날려따..더 바빴움..) 프로젝트를 진행하면서 스스로 코드를 짜보고, 구글링하고, 디버깅하는 과정에서 많은 것을 배웠다. 이전에 배웠던 것들을 잘 활용해볼 수 있는 기회였다.
오늘 배운 정규표현식도 머지 않아 프로젝트에서 자연스럽게 녹여낼 수 있도록 오늘은 내용 정리, 복습 TIL을 작성한다!

이번 TIL은 플레이데이터 수업 예제 복습과 함께 『점프 투 파이썬』을 참고했다.
내용이 이해하기 쉽게 잘 정리되어 있으니, 정규표현식에 대해 더 자세히 알고 싶다면 위 링크를 추천한다👍



정규표현식이란?

정규 표현식(Regular Expressions)은 복잡한 문자열을 처리할 때 사용하는 기법으로, 파이썬만의 고유 문법이 아니라 문자열을 처리하는 모든 곳에서 사용한다(『점프 투 파이썬』).

정규 표현식을 사용하면 복잡한 문자열에서 특정 포맷의 문자열을 추출하거나, 변경하는 등의 처리를 효율적으로 할 수 있다.

메타 문자

※ 메타 문자란 원래 그 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자를 말한다(『점프 투 파이썬』).

< 정규 표현식의 메타 문자 >

  • [] : 문자 클래스
  • \d : 숫자와 매치 [0-9]
  • \D : 숫자가 아닌것과 매치 [^0-9]
  • \s : whitespace 문자와 매치 [\t\n\r\f\v]
  • \S : whitespace 문자가 아닌것과 매치 [^ \t\n\r\f\v]
  • \w : 문자 + 숫자 매치 [a-zA-Z0-9]
  • \W : 문자 + 숫자 아닌것과 매치 [^a-zA-Z0-9]
  • \\ : 문자로서의 역슬래시와 매치
  • . : 줄바꿈 문자인 \n을 제외한 모든 문자와 매치
  • * : * 바로 앞에 있는 문자가 0부터 무한대로 반복될 수 있다는 의미
  • + : + 바로 앞에 있는 문자가 최소 1 이상 반복된다는 의미
  • {} : {} 바로 앞에 있는 문자가 특정 횟수만큼 반복 ({n} : n회 반복, {n, m} : n~m회 반복)
  • ? : ? 바로 앞에 있는 문자가 있어도 되고 없어도 된다는 의미

re 모듈 메서드

파이썬은 정규 표현식을 지원하기 위해 re(regular expression의 약어) 모듈을 제공한다(『점프 투 파이썬』). re 모듈은 파이썬을 설치할 때 자동으로 설치되는 기본 라이브러리로 별도의 pip install 없이 python 파일 내에서 import re 후 사용가능하다.

< 정규 표현식 re 모듈 메서드 >

  • findall : 정규식과 매치되는 부분을 모두 찾아 리스트로 반환, `re.findall(패턴, 데이터 집합)
  • split : 정규식과 매치되는 부분을 기준으로 문장을 나눔, re.split(패턴, 데이터 집합)
  • sub : 정규식과 매치되는 부분을 다른 문자로 변경, re.sub(패턴, 대체문자, 데이터 집합)
  • compile : 정규식 패턴을 정규식 객체로 컴파일, re.compile(패턴)
  • match : 문자열의 처음부터 정규식과 매치되는지 조사, 매치되면 match 객체 반환, 매치되지 않으면 None 반환
  • search : 문자열 전체를 검색하여 정규식과 매치되는지 조사, 매치되면 match 객체 반환, 매치되지 않으면 None 반환

정규표현식 활용 예제

1. findall

  • findall : 정규식과 매치되는 부분을 모두 찾아 리스트로 반환
  • re.findall(패턴, 데이터 집합)
num = 'my number is 631215-1***** and yours is 721103-2*****'
num1 = 'my number is 631215-1***** and yours is 7t1103-2*****'

re.findall('\d{6}', num)   # num에서 6자리 숫자 추출
>> ['631215', '721103']
re.findall('\d{6}', num1)  # num1에서 6자리 숫자 추출(문자열이 있으면 제외)
>> ['631215']
ex1 = '큰 딸은 2014년에 작은 딸은 2018년에 태어났습니다. 현재는 2021년 입니다.'

re.findall('\d.+년', ex1)   # .+  : 다른 문자 반복 허용
>> ['2014년에 작은 딸은 2018년에 태어났습니다. 현재는 2021년']
re.findall('\d.+?년', ex1)  # .+? : 다른 문자 반복 없이 문자+년만
>> ['2014년', '2018년', '2021년']
ex2 = '''
tom의 설명에 따르면 모든 것이 그렇다고 단정 지으면 안된다고 했습니다. (tom, 2021) 하지만 톰은 모든 것을 단정 지었습니다. (톰, 2000) 제리는 이런 일이 있을 것이라 예견했습니다. (제리, 1930)'''

re.findall(r'\(.+\)', ex2)   # .+ : 다른 문자 반복 허용
>> ['(tom, 2021) 하지만 톰은 모든 것을 단정 지었습니다. (톰, 2000) 제리는 이런 일이 있을 것이라 예견했습니다. (제리, 1930)']
re.findall(r'\(.+?\)', ex2)  # .+? : 다른 문자 반복 없이 (문자)만
>> ['(tom, 2021)', '(톰, 2000)', '(제리, 1930)']

2. split

  • split : 정규식과 매치되는 부분을 기준으로 문장을 나눔
  • re.split(패턴, 데이터 집합)
text = '저는 사랑스런 강아지를 데리고 있어여, 정말 입니다. 그런데, 요즘은 정말 말을 안듣습니다! 어떻게 할까요?'

re.split(r'[,.?!]', text)     # ,.?! 문장부호를 기준으로 문장 나눔
>> ['저는 사랑스런 강아지를 데리고 있어여', ' 정말 입니다', ' 그런데', ' 요즘은 정말 말을 안듣습니다', ' 어떻게 할까요', '']

re.split('[\,\.\?\!]', text)  # 위와 동일, \로 문장부호 나눠 입력
>> ['저는 사랑스런 강아지를 데리고 있어여', ' 정말 입니다', ' 그런데', ' 요즘은 정말 말을 안듣습니다', ' 어떻게 할까요', '']
data = 'test1 : 35:test2 : 44:test3 : 37'

re.split(r':', data)  # :를 기준으로 문장 나눔
>> ['test1 ', ' 35', 'test2 ', ' 44', 'test3 ', ' 37']

3. 집합 자료형 set

: 집합(set)은 파이썬 2.3부터 지원하기 시작한 자료형으로, 집합에 관련된 것을 쉽게 처리하기 위해 만든 자료형이다.

  • 중복을 허용하지 않음
  • 순서가 없음(Unordered)
# 텍스트 파일 open, read
f = open('friends101.txt', 'r', encoding='utf-8')
sc101 = f.read()

# 등장인물 패턴 : 대문자 + 소문자 + ':'
char = re.compile(r'[A-Z][a-z]+:')

# sc101에서 위의 패턴을 갖춘 것 모두 찾음(중복 포함)
re.findall(char, sc101)

# set : 리스트 안에서 중복 제거하여 담는 자료형(type)
test_s = [1, 2, 3, 4, 5, 2, 4, 8, 8, 8, 10, 2, 1, 1]
print(set(test_s))
>> {1, 2, 3, 4, 5, 8, 10}

# sc101에서 위의 패턴을 갖춘 것들 모두 찾아 중복 제거
charSet = set(re.findall(char, sc101))
# char 패턴대로 findall 한 뒤 set하여 중복 제거
del_col = set(re.findall(char, sc101))

# 결과물의 자료형은 set
print(type(del_col))  # type : set

# 리스트로 형 변환
del_col_to_list = list(del_col)

4. 인덱스 슬라이싱

test = 'test: '

test1_1 = test[:-1]  # 처음부터 뒤에 한 자리 빼고
print(test + "!!!")
>> test: !!!
print(test1_1 + "!!!")
>> test:!!!

test1_2 = test[:-2]  # 처음부터 뒤에 두 자리 빼고
print(test1_2 + "!!!")
>> test!!!

test2 = re.sub(':', '', test)  # :를 ''로 대체 (: 삭제와 같은 효과)
print(test2 + "!!!")
>> test !!!
character = []

# 등장인물 이름 뒤 ':'를 슬라이싱으로 제거하여 character에 할당
for i in del_col_to_list:
    character += [i[:-1]]

print(del_col_to_list)  # ':'이 제거되지 않은 채 그대로 출력
print(character)        # 등장인물 이름만 출력

# 위 과정 한 줄로 정리
# 1. 등장인물 이름 부분 포멧으로 sc101에서 re.findall
# 2. 중복 제거를 위해 set으로 형 변환
# 3. set 타입의 데이터를 list로 형 변환
# 4. for문으로 뒤에 2글자(': ') 슬라이싱해서 character2에 할당
character2 = [x[:-2] for x in list(set(re.findall(r'[A-Z][a-z]+: ', sc101)))]
profile
사부작 사부작

0개의 댓글