정규표현식 알아보기

skyepodium·2021년 8월 15일
3

정규표현식은 어려워서 매번 구글링하고 블로그에 올라온 것 그냥 복사해서 사용하고 그랬는데, 해봅시다.
https://regexr.com/ 에서 함께 ㄱㄱ

1. 그룹

1) ()

괄호 안의 전체를 단 1개의 패턴으로 봅니다. 따라서 작성한 순서가 하나의 패턴으로 유지됩니다.

  • (18일) 총 1개가 매칭 되었습니다.
  • (18일) 은 18일 단 1개의 패턴을 의미합니다.

2) []

패턴의 집합을 의미합니다. 괄호 안에 있는 것을 각각 독립적인 패턴으로 보기 때문에 하나라도 만족하는 것을 찾습니다.

그렇기 때문에 내부의 순서는 지켜지지 않습니다.

  • (8, 1, 8, 일) 총 4개가 매칭 되었습니다.
  • [18일]은 1, 8, 일 총 3개의 패턴의 집합을 의미합니다.

2. []와 함께 쓰는 표현

1) [^패턴]

^은 대괄호[]와 안에서 not의 의미를 가집니다.

따라서, 내부의 패턴과 조합하면,

대괄호 안의 패턴과 일치하지 않는 모든 것을 찾습니다.

  • (8, 1, 8, 일) 4개와 매칭되지 않는 문자들을 모두 찾습니다.

2) 숫자 [0-9]

- 은 대괄호 안에서 x부터 y까지의 의미를 가집니다.

  • [0-9] 는 0123456789를 의미합니다. (8, 1, 8) 3개가 매칭됩니다

3) 영소문자[a-z]

  • [a-z] 는 영소문자를 의미합니다.

4) 영대문자 - [A-Z]

  • [A-Z] 는 영대문자를 의미합니다.

앞에서 배운것을 모두 함께 사용하면

영소문자, 영대문자 그리고 숫자에 매칭된 모든것을 찾습니다.

5) 한글 - [ㄱ-ㅎㅏ-ㅣ가-힣]

  • [ㄱ-ㅎㅏ-ㅣ가-힣]는 한글을 의미합니다.

워워, 생긴것이 난해하지만, 자 후달리지 맙시다.

지금까지의 것들을 하나씩 생각해봅시다.

x-y 은 x부터 y까지를 의미합니다.

그럼

  • [ㄱ-ㅎ] - ㄱ부터 ㅎ까지 자음 전체
  • [ㅏ-ㅣ] - ㅏ부터 ㅣ까지 모음 전체
  • [가-힣] - 사전순으로 올 수 있는 가 부터 제일 마지막 힣까지 글자 전체

자음[ㄱ-ㅎ], 모음[ㅏ-ㅣ] 한글 [가-힣] 모두 매칭됩니다.

3. 대표 문자

1) 숫자 - \d

숫자를 의미하며, 0123456789 에 해당합니다. [0-9]와 같습니다.

[0-9] 있는데 \d 왜 사용함?

간단하게 사용하라고

2) 단어 영문자, 숫자, 밑줄 - \w

문자를 의미하며, 단어 영문자+숫자+(밑줄) 에 해당합니다. [0-9a-zA-Z] 와 같습니다.

생각보다 헷갈림, 문자 -> word -> \w 이렇게 느껴지는데 숫자도 들어가고 다르니까..
영문자 찾는다면 [a-zA-Z] 추천

4. 개수

1) {개수}

1개만 적으면 개수만큼 패턴이 반복되는 것만 찾습니다.

2) {최소, 최대}

{최소, 최대} 로 바로 앞의 패턴의 개수를 지정합니다.

숫자가 1개인 것들을 총 3개입니다. (8, 1, 8)

3) {최소, }

패턴이 최소이상 만큼 반복되는 것만 찾습니다.

{, 최대} 는 없습니다.

5. 유무

1) ? - 없거나 1개 있거나

2) * - 없거나 1개 있거나 많거나

3) + - 1개 있거나 많거나

6. 실습

자주 사용되는 예제를 통해 알아봅시다.

1) 핸드폰 번호

01\d-\d{3,4}-\d{4}|01\d\d{3,4}\d{4}

다음의 경우만 옳습니다.

  • -가 없거나 1개 있거나
    010-1234-5678
    01012345678

단, 010-12345678, 0101234-5678 은 안됨

  • 01x로 시작
    017-1234-5678
    01712345678

  • 가운데 3자리
    010-123-5678
    0101235678

이렇게 있으면 제일 쉽게 생각하면
\d\d\d-\d\d\d\d-\d\d\d\d

조금 줄여주면
01\d-\d{3,4}-\d{4}

-이 없는 경우도 있으니까 or로 없는 경우도 묶어주면
01\d-\d{3,4}-\d{4}|01\d\d{3,4}\d{4}

import re

def main(s):
    return re.fullmatch("01\d-\d{3,4}-\d{4}|01\d\d{3,4}\d{4}", s)

s_list = [
    "010-1234-5678",
    "01012345678",
    "017-1234-5678",
    "01712345678",
    "010-123-5678",
    "0101235678",
    "안녕하세요",
    "123",
    "abcde",
    "010-1235678",
    "0101234-5678",
    "011322345"
]

for s in s_list:
    res = "correct" if main(s) else "error"
    print(res, s)
"""
correct 010-1234-5678
correct 01012345678
correct 017-1234-5678
correct 01712345678
correct 010-123-5678
correct 0101235678
error 안녕하세요
error 123
error abcde
error 010-1235678
error 0101234-5678
error 011322345
"""

2) 돈, 세자리 콤마

\d{1,3}(,\d{3})+|\d|[1-9]{1}\d*

다음의 3가지 경우에만 옳은 것으로 판단합니다.

  • 1000 - 숫자로만 이루어짐
  • 1,000 - 3자리 씩 콤마로 구분
  • 0 - 0으로 시작하는 경우 1자리만 가능

하나씩 생각해보면
\d\d\d,\d\d\d,\d\d\d

조금 줄여보면,
\d{1,3}(,\d{3})+

한자리인 경우 or로 포함하면
\d{1,3}(,\d{3})+|\d

0이 아닌 숫자로 시작하는 경우 or로 포함하면
\d{1,3}(,\d{3})+|\d|[1-9]{1}\d*

import re


def main(money):
    return re.fullmatch("\d{1,3}(,\d{3})+|\d|[1-9]{1}\d*", money)

s_list = ["Hello", "-123", "10,000원", "0123", "0", "1", ",123", "1,123", "1234"]

for s in s_list:
    res = "correct" if main(s) else "error"
    print(res, s)
    
"""
error Hello
error -123
error 10,000원
error 0123
correct 0
correct 1
error ,123
correct 1,123
correct 1234
"""

3) 문자열 정제

"[삼성전자] 갤럭시 Z폴드3 - 3,000,000원",
"[APPLE] 아이폰 12 Pro - 1,300,000원"

위와 같은 문자열 리스트가 주어졌을 때

1) 브랜드 이름, 2) 상품명, 3) 가격(콤마 제외)를 반환하세요.

import re

def main(s):
    # 1. brand_name
    brand_name = re.search("\[(([ㄱ-ㅎ가-힣ㅏ-ㅣ]+)|[a-zA-Z0-9]+)\]", s).group()
    brand_name = brand_name[1:len(brand_name)-1]

    # 2. product_name
    product_name = re.search("\] [ㄱ-ㅎ가-힣ㅏ-ㅣa-zA-Z0-9 ]+-", s).group()
    product_name = product_name[2:len(product_name)-2]

    # price
    price = re.search("- (\d{1,3}(,\d{3})+|\d|[1-9]{1}\d*)원", s).group()
    price = price[2:len(price)-1].replace(",","")

    return brand_name, product_name, price


s_list = [
    "[삼성전자] 갤럭시 Z폴드3 - 3,000,000원",
    "[APPLE] 아이폰 12 Pro - 1,300,000원"
]

for s in s_list:
    brand_name, product_name, price = main(s)
    print("brand_name:", brand_name, "product_name:", product_name, "price:", price)
    
"""
brand_name: 삼성전자 product_name: 갤럭시 Z폴드3 money: 3000000
brand_name: APPLE product_name: 아이폰 12 Pro money: 1300000
"""
profile
callmeskye

0개의 댓글