python/파이썬 기본

11. 정규표현식 re module

Abokadoh 2023. 2. 13. 15:33

1. 정규표현식이란 (regular expression)

  • 특정한 패턴과 일치하는 문자열을 ‘검색’, ‘치환’, ‘제거’하는 기능을 지원한다.
  • 정규표현식의 도움없이 패턴을 찾는 작업(Rule 기반)은 불완전 하거나, 작업의 cost가 높다.
    • 이메일 형식을 판별, 전화번호 형식 판별, 숫자로만 이루어진 문자열 등…

- raw string

문자열 앞에 r이 붙으면 해당 문자열이 구성된 그대로 문자열로 반환한다.

# <in>
a = 'abcdef\n' #\n은 newline 명령어임
print(a)

b = r'abcdef\n' #문자열 앞에 r을 붙임으로써 \n을 그대로 문자열로 취급
print(b)


# <out>
abcdef

abcdef\n

2. 정규표현식 기본 패턴

  • a, X, 9 등 문자 하나하나의 character들은 정확히 해당 문자와 일치한다.
    • e.g) 패턴 test는 test 문자열과 일치한다.
    • 대소문자의 경우 기본적으로는 구별하나, 구별하지 않도록 설정도 가능하다.
  • 몇몇 문자들에 대해서는 예외가 존재하는데, 이들은 특별한 의미로 사용된다.
    • . ^ $ * + ? {} [] \ | ()
  • .(마침표) 어떤 한개의 character와 일치 (newline(엔터) 제외) 어떤 character 든 인식한다는 말인 것 같다. 단, 엔터 제외
  • \w 문자 character와 일치 [a-zZ-Z0-9] \w는 특수문자는 취급하지 않는 것으로 보인다. 특수문자 취급은 위에 마침표(.)
  • \s 공백문자와 일치
  • \t, \n, \r tab, newline, return
  • \d 숫자 character와 일치 [0,9]
  • ^ → 시작, $ 끝 각각 문자열의 시작과 끝을 의미한다.
  • \가 붙으면 스폐셜한 의미가 없어짐, 예를들어 \.는 .자체를 의미 \\는 \를 의미
  • 자세한 내용은 링크

re - Regular expression operations

 

re — Regular expression operations

Source code: Lib/re/ This module provides regular expression matching operations similar to those found in Perl. Both patterns and strings to be searched can be Unicode strings ( str) as well as 8-...

docs.python.org

3. re.search()

  • 첫번째로 패턴을 찾으면 match 객체를 반환
  • 패턴을 찾지 못하면 None을 반환
# <in>
import re

m = re.search(r'abc', '123abcdef')
n = re.search(r'abc', '123abdef')
print(m)
print(n)

type(m)
type(n)


# <out>
<re.Match object; span=(3, 6), match='abc'>
None

re.Match
NoneType
# <in>
m = re.search(r'/d/d/d/w', '112abcdef119') #숫자숫자숫자문자 
# 첫번째로 패턴을 찾으면 match객체를 반환 112a
m

n = re.search(r'..\w\w', '@#$%ABCDabcd')
# ..은 any character, \w은 any 문자
print(m)
print(n)


# <out>
None
<re.Match object; span=(2, 6), match='$%AB'>

4. metacharacters  /  [ ]로 문자 범위 나타내기

[ ]로 문자들의 범위를 나타낼 수 있다.

  • [ ] 내부의 메타 캐릭터는 캐릭터 자체를 나타냄
  • e.g)
    • [abck] : a or b or c or k
    • [abc.^] : aor b or c or . or ^
    • [a-d] : -와 함께 사용되면 해당 문자 사이의 범위에 속하는 문자 중 하나
    • [0-9] : 모든 숫자
    • [a-z] : 모든 소문자
    • [A-Z] : 모든 대문자
    • [a-zA-Z0-9] : 모든 알파벳 문자 및 숫자
    • [^0-9] ^가 맨 앞에 사용되는 경우 해당 문자 패턴이 아닌 것과 매칭한다.
# <in>
m = re.search(r'[cbm]at','aat') #c or b or m
m # None return
n = re.search(r'[cbm]at','cat')
n # cat return

m = re.search(r'[0-4]haha','7haha') 
m # None [0-4]엔 7이 없으므로

n = re.search(r'[abc.^]aron','daron') 
n # None 
m = re.search(r'[abc.^]aron','^aron')
m

5. \d, \D, \s, \S, \w, \W, \., \\ 사용하기

  1. 다른 문자와 함께 사용되어 특수한 의미를 지닌다.
  • \d : 숫자를 [0-9]와 동일
  • \D : 숫자가 아닌 문자 [^0-9]와 동일
  • \s : 공백 문자(띄어쓰기, 탭, 엔터 등)
  • \S : 공백이 아닌 문자
  • \w : 알파벳대소문자, 숫자 [0-9a-zA-Z]와 동일
  • \W : non alpha-numeric 문자 [^0-9a-zA-A]와 동일
  • 메타 캐릭터가 캐릭터 자체를 표현하도록 할 경우 사용
  • \. , \\
# <in>
m = re.search(r'\Sand','apple and banana') # \S : 공백이 아닌 문자
m # and 출력안됨 \Sand -> and앞에 공백이 없는 문자열은 match하기 때문

m = re.search(r'\Sand','apple land banana')
m # land를 출력하겠지요?

re.search(r'\.and','.and') # .을 캐릭터 자체로 표현하고 싶을 때 \를 사용

6. 정규표현식에서 . 의 의미

  • 모든 문자를 의미한다.

7. 정규표현식 반복패턴 사용

  • 패턴 뒤에 위치하는 *, +, ?는 해당 패턴을 반복적으로 존재하는지를 검사한다.
    • ‘+’  1번 이상의 패턴이 발생
    • ‘*’ 0번이상의 패턴이 발생
    • ‘?’ 0혹은 1번의 패턴이 발생
  • 반복을 패턴의 경우 greedy하게 검색한다. 가능한 많은 부분이 매칭되도록 한다.
    • e.g) a[bcd]*b 패턴을 abcbdccb에서 검색하는 경우
    • ab, abcb, abcbdccb 전부 매칭이 가능하지만 최대한 많은 부분이 매칭된 abcbdccb가 반한된다.
# <in>
re.search(r'a[bcd]*b','abcbdccb')

re.search(r'b\w+a', 'banana')

re.search(r'i+','piigiii')

re.search(r'pi+g','pg')

re.search(r'pi*g','pg')

re.search(r'https?','http://www.naver.com')

 

8. ^, $ (맨 앞,뒤부터 일치하는 것 검색하기)

  • ^ 문자열의 맨 앞부터 일치하는 경우 검색
  • $ 문자열의 맨 뒤부터 일치하는 경우 검색
# <in>
re.search(r'b\w+a','cabana')

re.search(r'^b\w+a','cabana')

re.search(r'^b\w+a','babana')

re.search(r'b\w+a$', 'cabana')

re.search(r'b\w+a$', 'cabanap')

9. grouping

  • () 을 사용하여 그룹핑
  • 매칭 결과를 각 그룹별로 분리 가능
  • 패턴 명시 할 때, 각 그룹을 괄호()안에 넣어 분리하여 사용가능
# <in>
m = re.search(r'(\w+)@(.+)'m 'test@gmai.com')
print(m.group(1))
print(m.group(2))
print(m.group(0))


# <out>
test
gmai.com
test@gmai.com

 

10. {}을 사용하여 반복 횟수 제한하기.

  • *, +, ?을 사용하여 반복적인 패턴을 찾는 것이 가능하지만, 반복의 횟수를 제한할 수 없다.
  • 패턴뒤에 위치하는 중괄호 {}에 숫자를 명시하면 해당 숫자 만큼의 반복인 경우메나 매칭한다.
  • {4} $\Rightarrow$ 4번 반복
  • {3,4} $\Rightarrow$ 3~4번 반복
# <in>
re.search('pi{3,5}g','piiiiig')

미니멈 매칭 (non-greedy way)

  • 기본적으로 *, +, ?을 사용하면 greedy(맥시멈 매칭)하게 동작한다.
  • *?, +?을 이용하여 해당 기능을 구현할 수 있다.
# <in>
re.search(r'<.+>','<html>haha</html>')

re.search(r'<.+?>','<html>haha</html>')


# <out>
<re.Match object; span=(0, 17), match='<html>haha</html>'>
<re.Match object; span=(0, 6), match='<html>'>

{}?를 사용해서 non-greedy하게

  • {m,n}의 경우 m번에서 n번 반복하나 greedy하게 동작한다.
  • {m,n}?로 사용하면 non-greedy하게 동작한다. 즉, 최소 m번만 매칭하면 만족
# <in>
re.search(r'a{3,5}','aaaaa')

re.search(r'a{3,5}?', 'aaaaa')


# <out>
<re.Match object; span=(0, 5), match='aaaaa'>
<re.Match object; span=(0, 3), match='aaa'>

match 사용법

  • search와 유사하나, 주어진 문자열의 시작부터 비교하여 패턴이 있는지 확인한다.
  • 시작부터 해당 패턴이 존재하지 않으면 None을 반환
# <in>
re.match(r'\d\d\d', 'my number is 123')

re.match(r'\d\d\d', '123 is my number')

re.search(r'^\d\d\d', '123 is my number')


# <out>
None
<re.Match object; span=(0, 3), match='123'>
<re.Match object; span=(0, 3), match='123'>

findall 사용법

  • search가 최초로 매칭되는 패턴만 반환한다면, findall은 매칭되는 전체의 패턴을 반환한다.
  • 매칭되는 모든 결과를 리스트 형태로 반환
# <in>
re.findall(r'[\w-]+@[\w.]+', 'test@gmail.com haha test2@gmail.com nice test test')


# <out>
['test@gmail.com', 'test2@gmail.com']

sub 사용법

  • 주어진 문자열에서 일치하는 모든 패턴을 replace
  • 그 결과를 문자열로 다시 반환함
  • 두번째 인자는 특정 문자열이 될 수도 있고, 함수가 될 수도 있음
  • count가 0인 경우는 전체를, 1이상이면 해당 숫자만큼 치환 됨
# <in>
re.sub(r'[\w-]+@[\w.]+','love', 'test@gmail.com haha test2@gmail.com nice test test', count = 1)


# <out>
'love haha test2@gmail.com nice test test'

complie 사용법

  • 동일한 정규표현식을 매번 다시 쓰기 번거로움을 해결
  • complie로 해당표현식을 re.RegexObject 객체로 저장하여 사용가능하다.
# <in>
email_reg = re.compile(r'[\w-]+@[\w.]+')
email_reg.search('test@gmail.com haha good')
email_reg.findall('test@gmail.com haha good haha plus@naver.com')


# <out>
<re.Match object; span=(0, 14), match='test@gmail.com'>
['test@gmail.com', 'plus@naver.com']