티스토리 뷰

프로그래밍/Python

정규 표현식

꼬렙 2023. 8. 4. 19:42
728x90

정규 표현식(Regular Expressions)은 특정 패턴의 문자열을

검색하거나 편집하는데 사용되는 강력한 도구입니다.

 

파이썬에서 정규식을 사용하기 위해 re 모듈을 사용할 수 있고

이 모듈은 정규식을 처리하는데 필요한 여러가지 함수를 제공합니다.

 

 

정규식이 유용하게 사용되는 경우

 

1. 데이터 유효성 검사 : 데이터의 형식이 올바른지 확인할 때 사용

    ex) 이메일 주소, 전화번호, 주민등록번호, 계좌번호 등

 

2. 텍스트 편집 : 텍스트 문서나 문자열에서 특정 패턴을 찾아 바꾸거나 삭제하는 작업

    ex) ,(comma) 다음에 줄바꿈으로 작성된 모든 문자의 행을 ;(semi colon) 으로 변경

          글자와 글자 사이에 입력된 2개 이상의 공백은 1개로 변경 등

 

3. 로그 분석 : 원하는 정보를 추출하거나 특정 패턴을 분석하는데 사용

    ex) 내용 중 IP주소, 요청 URL 추출

 

4. 데이터 수집 : 웹 페이지 등에서 원하는 데이터만 추출

    ex) 로또사이트에서 1등 번호만 추출, 웹툰 사이트에서 웹툰의 제목만 추출

 

위 내용은 3가지로 정리할 수 있습니다.

1. 검사 - 문자 존재 여부 확인 (find)

2. 추출 - 문자 잘라내기 (slicing)

3. 치환 - 문자 바꾸기 (replace)

 

 

정규식을 사용하려면 몇가지 기호(문자) 사용법을 숙지해야 하는데

크게 2가지로 나눌 수 있습니다.

 

1. 단독으로 사용할 수 있는 기호

2. 1번의 기호를 보조하는 기호


먼저 단독으로 사용할 수 있는 기호들 입니다.

[] \d \D \s \S \w \W .

[]

1. 대괄호 사이에 문자를 입력(나열)하는 방식으로 사용

    입력된 문자들은 or의 의미로 적용

2. - 기호를 사용하면 범위 표현이 가능

3. ^ 기호를 사용하면 부정의 의미

ex) [abc] → a or b or c
      [0-9] → 0 or 1 or 2 or ...  9
      [A-D] → A or B or C or D
      [1A가] → 1 or A or 가

\d \s \w \D \S \W

1. d는 digit, s는 space, w는 word

2. d는 모든 숫자, s는 공백 / 탭 / 줄바꿈, w는 알파벳(대소문자) / 숫자 / 각 나라의 문자 / _(밑줄)을 의미

    w의 경우 일반적으로 얘기하는 특수문자는 제외 ex) @ # $ 등

3. 대문자는 부정의 의미

ex) \d → [0-9]
      \s → [ \n\t]  # 실제로는 [ \n\t\r\f\v] 이지만 \r \f \v 는 거의 사용하지 않음
              \r 줄의 처음으로 이동 문자, \f 페이지 넘김 문자, \v 수직 탭
      \w → [a-zA-Z0-9_...]

.

1. 줄바꿈 문자인 \n을 제외한 모든 문자를 의미

2. 대괄호 내에서 .을 사용하거나 \(back slash) 다음에 .을 사용하면 . 자체로 인식

ex) a.b → aab, abb, azb, atb, a가b, a0b, ....
      a[.]b → a.b

다음은 단독으로 사용할 수 있는 기호를 보조하는 기호입니다.

* + {} ? ^ $ | ()

* 바로 앞의 기호가 0회 이상 반복

ex) a*b → ab, aab, aaaaaaaaaaaab, b
      \d*회 → 0회, 1회, 2회, 9999999999회, 회
      \W*p → @p, !p, &p, "p, <p, p

+ 바로 앞의 기호가 1회 이상 반복

ex) a+b → ab, aab, aaaaaaaaaaaaab
      \d+회 → 0회, 1회, 2회, 9999999999회
      \W+p → @p, !p, &p, "p, <p

{}  띄어쓰기 주의

1. {n} 바로 앞의 기호가 n회 반복

2. {n,m} 바로 앞의 기호가 n회 이상, m회 이하 반복

3. {n,} 바로 앞의 기호가 n회 이상 반복

4. {,m} 바로 앞의 기호가 m회 이하 반복

ex) a{2}b → aab
      a{1,3}b → ab, aab, aaab
      a{3,}b → aaab, aaaab, aaaaab, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
      a{,1}b → b, ab

?

1. 바로 앞의 기호가 0회 이상 1회 이하 반복

2. Non greedy 동작

ex) a?b → b, ab
     
     ※ Non greedy
         "aa.bb.cc.dd.ee." 문자열에 .+[.] 정규식을 적용하면
         aa.bb.cc.dd.ee. 모든 문자가 정규식과 일치한다고 판단합니다.
         .+?[.]  이렇게 + 기호 다음 ? 를 사용하면 aa. 만 일치한다고 판단하게 됩니다.

^

1. 바로 뒤 기호로 시작

2. 대괄호 안에서 사용하면 부정을 의미

ex) ^abc → abc
      [^abc] → a or b or c 를 제외한 모든 문자

$ : 바로 앞 기호로 종료

ex) [ab]+\d$ → aaaa1, ab0, aaaaaaaa9, bbbbbbbbb7

| : 여러 패턴 중 하나

ex) ^Hello | \d{2} | Good[.]$ → Hello, 00, 12, 87, Good.

()

1. 괄호 안의 패턴을 그룹화

2. re 모듈의 함수 중 findall을 사용하면 해당하는 문자를

    모두 리스트의 요소로 생성 (해당하는 모든 문자 추출)

ex) \d{3}-\d{4}-(\d{4}) → 010-1234-5678 → 5678
      오류코드\s*:\s*(\d+) → 오류코드 : 404 → 404

파이썬에서 정규식을 표현하기 위한 기본 코드입니다.

import re
pattern = re.compile('정규식')
result = pattern.search('문자데이터')
print(result)

compile() 은 정규식의 패턴을 지정하기 위한 필수이고

search() 는 패턴에 맞는 문자를 검사하거나 추출하기 위한 함수입니다.

 

1개의 결과를 얻으려면 match() 와 search()

N개의 결과를 얻으려면 findall() 과 finditer()를 사용하면 되는데

 

1개 일때는 search()

N개 일때는 findall()을 사용하면 결과를 편하게 얻을 수 있습니다.

 

 

search()와 findall()을 적용하는 예시입니다.

 

1개 search()
import re
text = '#짜장면, #냉면, #밀면, #삼겹살'
pattern = re.compile('#\w+')
result = pattern.search(text)
print(result)  # <re.Match object; span=(0, 4), match='#짜장면'>

 

N개 findall()
import re
text = '#짜장면, #냉면, #밀면, #삼겹살'
pattern = re.compile('#\w+')
result = pattern.findall(text)
print(result)  # ['#짜장면', '#냉면', '#밀면', '#삼겹살']

 

findall()은 매칭되는 문자들을 리스트의 요소로 출력하는 것에 비해
search()는 알아보기 힘든 결과를 출력합니다.
search()를 사용하면서 깔끔한 결과를 얻으려면 group() 이라는 함수를 적용해주면 됩니다.

import re
text = '#짜장면, #냉면, #밀면, #삼겹살'
pattern = re.compile('#\w+')
result = pattern.search(text)
print(result.group())  # #짜장면

 

패턴으로 작성된 내용을 그대로 매칭하는 것이 기본이고

매칭된 내용 중 일부분만 결과로 얻으려면 원하는 부분을 그룹화시켜 주면 됩니다.

 

위의 데이터에서 "짜장면", "냉면" 과 같이 한글만 추출하는 예시입니다.

import re
text = '#짜장면, #냉면, #밀면, #삼겹살'
pattern = re.compile('#(\w+)')
result = pattern.search(text)
print(result.group(1))  # 짜장면
import re
text = '#짜장면, #냉면, #밀면, #삼겹살'
pattern = re.compile('#(\w+)')
result = pattern.findall(text)
print(result)  # ['짜장면', '냉면', '밀면', '삼겹살']

findall()은 그대로 사용하면 되고

search()의 경우는 그냥 group()이 아닌 group(괄호순번)으로 사용해야 됩니다.

 

() 그룹화를 2개 사용했다면 group(1)과 group(2)로 지정합니다.