고양국제고/더브레인

[더브레인-3] 1. 정규표현식 예제 실습 안내

카루-R 2022. 7. 7. 14:43
반응형
 

환영합니다, Rolling Ress의 카루입니다.

** 3-1: 정규표현식 - 언어/통계

오늘은 제가 따로 설명을 하지 않겠습니다. 본 글을 보고 진행해주시고, 질문 사항이 있을 경우에만 불러주세요. 이번 글은 정규표현식에 관한 내용으로, 사실상 여러분 모두가 이 예제를 해보셨으면 하는 바람이 있습니다. 내용이 다소 어려운 관계로, 길게 하진 않겠습니다. 사실 정규표현식만 다루는 책이 수두룩할 정도로 내용이 많아요.

정규표현식(Regular Expression)은 자연어 처리에서 매우 중요한 역할을 합니다. 특히 데이터 전처리에서 빛을 발하죠. 문자열의 특징을 추출하거나 패턴을 찾을 때 유용하게 쓸 수 있습니다. 알아두면 정말 쓸 데가 많아요. 단순히 Ctrl+H 눌러서 바꾸기 하는 것도 정규표현식으로 유용하게 쓸 수 있는데... TMI는 넘깁시다.

# 정규표현식 라이브러리
import re

target_list = ['237489@ggg.hs.kr', 'blog.naver.com', 'karu@',
    'karu@naver.com', '829yh2f@hola']
regex_email = r'^[a-zA-Z0-9+-\_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'

regex = re.compile(regex_email)
for target in target_list:
    print(f'타겟 문자열: {target}')
    if regex.match(target) == None:
        print('올바른 이메일 주소가 아닙니다.\n')
    else:
        print('올바른 이메일 주소입니다.\n')

시작해봅시다. 참고로 \\는 같은 기호입니다. 폰트에 따라서 달라보일 수 있어요. 일단 빈칸을 빠짐없이 채워주신 뒤, 실행해주세요.

이제 코드를 한 줄씩 분석해봅시다.

regex = re.compile(regex_email)
정규표현식을 사용하기 위한 문장입니다. regex_email 부분에 정규표현식 문자열을 넣으면 됩니다.
if regex.match(target) == None:

match() 함수는 주어진 문자열(target)이 정규표현식 패턴과 일치하면 특정 개체를 반환하고, 그렇지 않으면 None(값이 없는 상태)을 반환합니다. 이 문장은 '만약(if) 주어진 문자열(target)이 정규표현식(regex)과 일치하지 않으면(== None)'으로 해석할 수 있습니다.

^[a-zA-Z0-9+-\_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$

그렇다면 이 정규표현식을 자세히 봅시다. 이게 뭔 외계어인지 싶으실텐데, 차근차근 하나씩 분해해봅시다.

 

regex101: build, test, and debug regex

Regular expression tester with syntax highlighting, explanation, cheat sheet for PHP/PCRE, Python, GO, JavaScript, Java, C#/.NET.

regex101.com

 

참고로 직접 테스트를 하고 싶으신 분들은 위 사이트에 들어가주세요. regex101이라는 사이트인데, 정규표현식을 테스트하고 여러 문자열을 검출해볼 수 있습니다. 해설까지 제공해주는데, 영어라는 게 단점. 여튼, ^는 문자열의 시작, $는 문자열의 끝을 의미합니다. 쉽게 말해 ^뒤에 오는 걸로 시작하고 $ 앞에 오는 걸로 끝나야 한다는 뜻입니다.

[a-zA-Z0-9+-\_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+

중간에 껴있는 @과 \.을 기준으로 나누어 보겠습니다. 아무런 표시 없이 저렇게 문자가 띡 있는 건 "해당 문자가 반드시 있어야 함"을 나타낸다고 보시면 됩니다. 정규표현식에서 마침표는 특수문자로 인식하기 때문에 그냥 마침표를 나타내려면 앞에 역슬래시(\)를 붙여줘야 합니다.

[a-zA-Z0-9+-\_.]+ @ [a-zA-Z0-9-]+ \. [a-zA-Z0-9-.]+

[] 대괄호로 둘러싸인 것들은 '대괄호 안에 있는 게 하나라도 있어야 한다'를 뜻합니다. +는 그런 문자가 '한 개 이상' 반복되어야 한다는 것을 나타냅니다.

[a-zA-Z0-9+-\_.]

그럼 이 대괄호를 볼까요. 소문자 a부터 z까지, 대문자 A부터 Z까지, 그리고 +부터 _까지의 일부 특수문자를 잡아낸다는 뜻입니다. '.'은 그냥 '.'입니다.

regex_phone = r'\d{2,3}-\d{3,4}-\d{4}'
phone_text = '''환영합니다, Rolling Ress의 카루입니다.
오늘은 제가 배가 고파서 짜장면을 시켜먹어볼까 해요.
음.. 어디보자. 전단지가 어디있더라... 아, 찾았다!
031-839-5080... 여보세요? 중국집인가요?
아 고양국제고등학교 교무실이라고요? 죄송합니다. 잘못 걸었습니다.'''

print('추출된 전화번호:', re.search(regex_phone, phone_text).group())

두 번째 예제입니다. 이번에는 줄글에서 우리가 찾고자 하는 정보를 빠르게 찾아내는 방법을 알아보겠습니다. 입력하고, 실행해주세요.

참고로 저 번호는 고양국제고등학교 3학년부 전화번호입니다. 함부로 막 전화 걸고 그러시면 곤란합니다 ^^,,,, (학교홈페이지에 공개되어 있는 정보라 그냥 사용했습니다)

\d{2,3}-\d{3,4}-\d{4}

\d는 임의의 숫자를 뜻합니다. 즉, \d는 [0-9]와 완전히 같은 표현입니다. 특정 문자 뒤에 중괄호가 붙으면 반복하라는 뜻입니다. \d{2,3}은 2개 이상 3개 이하, \d{4}는 정확히 4개를 뜻합니다. 즉, 00-000-0000 내지는 000-0000-0000 등의 전화번호를 모두 찾아낼 수 있는 거죠.

re.search(regex_phone, phone_text).group()

아까처럼 re.compile() 함수를 사용해도 되지만 이번에는 바로 출력하겠습니다. 위 줄글에서 전화번호 패턴을 찾으면 그 값을 반환하도록 코딩한 겁니다. 그래서 우리는 이것만으로 전화번호를 추출할 수 있는 거죠.

 
script = """
[Borachio] What Conrade!
[Watchman] Peace! stir not.
[Borachio] Conrade, I say!
[Conrade] Here, man; I am at thy elbow.
[Borachio] Mass, and my elbow itched.
"""
result_list = list(set(re.findall(r'\[(\w+)\]', script)))
print(result_list)

마지막 예제입니다. 원래 하나 더 추가하려고 했는데, 여러분 머리가 터질 것 같아서 이걸로 끝내겠습니다. 본 예제는 대본에서 대괄호를 찾아 그 안에 있는 내용을 캡처하는 겁니다. 희곡 같은 데에서 등장인물들 목록 따올 때 편리하겠죠. 마지막에 list(set( 이렇게 한 이유는 중복을 제거하기 위해서입니다.

따로 과제는 드리지 않겠습니다. 여기까지 완료하신 분들은 제게 보여주시고, 다음 예제를 진행해주세요.

반응형