마케팅/데이터분석(파이썬)

(파이썬/python) 모두를 위한 프로그래밍 : 파이썬 챕터 11 / 정규식

정규식 간단한 요약

정규 표현식의 규칙에 대해 간단히 요약한 내용입니다. 앞으로 이 내용에 대해 예제와 함께 차근차근 설명을 드리도록 하겠습니다.

 

^ : 라인의 처음을 매칭

$ : 라인의 끝을 매칭

. : 임의의 문자를 매칭(와일드 카드)

₩s : 공백 문자를 매칭

₩S : 공백이 아닌 문자를 매칭

* : 바로 앞선 문자에 적용되고 0 혹은 그 이상의 앞선 문자와 매칭을 표기함.

*? : 바로 앞선 문자에 적용되고 0 혹은 그 이상의 앞선 문자와 매칭을 탐욕적이지 않은 방식으로 표기함.

+ : 바로 앞선 문자에 적용되고 1 혹은 그 이상의 앞선 문자와 매칭을 표기함.

+? : 바로 앞선 문자에 적용되고 1 혹은 그 이상의 앞선 문자와 매칭을 탐욕적이지 않은 방식으로 표기함.

[aeiou] : 명세된 집합 문자에 존재하는 단일 문자와 매칭. "a", "e", "i", "o", "u" 문자만 매칭되는 예제

[a-z0-9] : - 기호로 문자 범위를 명세할 수 있다. 소문자이거나 숫자인 단일 문자만 매칭되는 예제

() : 괄호가 정규표현식에 추가될 때, 매칭을 무시한다. 하지만 findall()을 사용할 때 전체 문자열보다 매칭된 문자열의 상세한 부속 문자열을 추출할 수 있게 한다.

 

텍스트에서 문자 패턴 찾기

다음 코드는 mbox-short.txt 파일에서 'From:'이라는 문자 패턴이 포함된 문장을 찾아 출력하는 프로그램입니다. 여기에서는 find() 메소드를 사용했습니다.

improt re

hand = open('mbox-short.txt')
for line in hand:
    line = line.rstrip()
    if line.find('From:') >= 0:
        print(line)

#같은 프로그램을 정규표현식을 활용해 작성한다면?
#re.search()가 find() 메소드의 역할을 수행

improt re

hand = open('mbox-short.txt')
for line in hand:
    line = line.rstrip()
    if re.search('From:',line):
        print(line)

 

텍스트에서 시작 패턴 찾기

이번에는 'From:'으로 시작하는 문장을 출력하는 프로그램입니다.

import re

hand = open('mbox-short.txt')
for line in hand:
    line = line.rstrip()
    if line.startswith('From:'):
        print(line)

#정규표현식에서는 ^ 특수문자를 사용

import re

hand = open('mbox-short.txt')
for line in hand:
    line = line.rstrip()
    if re.search('^From:', line):
        print(line)

 

특수 문자를 활용한 문자 패턴 찾기

 

정규 표현식의 다양한 특수 문자

^ : 문장의 시작을 의미

. : 어떤 문자 한 글자

* : 앞의 문자가 여러 번 반복될 수 있음을 의미

+ : 앞의 문자가 1번 이상 나타남을 의미

₩S : 공백 문자가 아닌 한 개의 문자

(₩는 역슬래시와 같은 문자)

 

따라서, 다음과 같은 문자열들은 모두 '^X.*:'라는 패턴을 통해 찾을 수 있습니다.

  • X-Sieve: CMU Sieve 2.3
  • X-DSPAM-Result: Innocent
  • X-DSPAM-Confidence: 0.8475
  • X-Content-Type-Message-Body: text/plain

그리고 다음과 같은 문자열들은 '^X-₩S+:' 패턴으로 찾을 수 있으며,

  • X-Sieve: CMU Sieve 2.3
  • X-DSPAM-Result: Innocent

다음의 문자열은 'X-'와 ':' 사이에 공백 문자가 아닌 문자가 포함되지 않았기 때문에 '^X-₩S+:' 패턴으로 찾을 수 없습니다.

  • X-: Very short
  • X-Plane is behind schedule: two weeks

패턴 추출하기

다음 코드에서 '[0-9]+'은 0부터 9까지 문자가 1번 이상 반복되는 패턴을 의미합니다. 이것은 즉, 정수로 이루어진 데이터를 찾는 것입니다. 또한 findall 메서드는 x라는 문자열에 존재하는 패턴('[0-9+]')을 모두 리스트로 저장해주는 기능을 합니다.

따라서, 이 코드는 x라는 문자열에서 정수 형태의 데이터를 모두 추출하여 y에 저장을 하는 코드입니다.

import re
x = 'My 2 favorite numbers are 19 and 42'
y = re.findall('[0-9]+', x)
print(y)

#['2','19','42']

import re
x = 'My 2 favorite numbers are 19 and 42'
y = re.findall('[AEIOU]+', x)
print(y)

#[] (빈 리스트로 출력)
#정규 표현식은 소문자와 대문자를 구분한다.

 

탐욕적 방식의 패턴 찾기

만약 다음 문장에서 '^F.+:'라는 패턴과 일치하는 부분을 찾는다면,

x = 'From: Using the : character'

  • From:
  • From: Using the :

이라는 두 가지 부분이 모두 패턴과 일치하게 됩니다.

이럴 때는 다음과 같이 가장 긴 패턴을 찾아주는데, 이것을 '탐욕적 방식의 패턴 찾기'라고 부릅니다. 일치하는 여러 패턴이 있을 경우 가장 긴 것을 선택한다는 의미입니다.

 

패턴 뒤에 '?'(물음표)를 붙여주면 여러 대상 중 가장 짧은 것을 선택합니다. 이것을 '비탐욕적 방식의 패턴 찾기'라고 합니다.

 

import re
x = 'From: Using the : character'
y = re.findall('^F.+:', x)
print(y)

#['From: Using the :']

import re
x = 'From: Using the : character'
y = re.findall('^F.+?:', x)
print(y)

#['From:']

 

원하는 부분만 추출하기

다음 코드를 실행하면 '@' 문자 앞 뒤로 공백이 아닌 문자가 오는 문자열 패턴을 찾아줍니다. 따라서 다음과 같이 이메일 주소의 패턴이 추출됩니다.

import re

x = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008'

y = re.findall('₩S+@₩S+', x)
print(y)

#['stephen.marquard@uct.ac.za']

#() 소괄호를 사용하여 From으로 시작하는 이메일 부분만 추출

import re
x = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008'

y = re.findall('^From (₩S+@₩S+)', x)
print(y)
#['stephen.marquard@uct.ac.za']

 

이메일 호스트를 추출하는 다양한 방법

#find 메소드와 리스트 슬라이싱 활용

data = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008'
atpos = data.find('@')
print(atpos)
#21
sppos = data.find('',atpos)
print(sppos)
#31
host=data[atpos+1 : sppos]
print(host)
#uct.ac.za

#split 메소드 활용

line = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008'
words = line.split()
email = words[1]
pieces = email.split(@)
print(pieces[1])

#uct.ac.za

#정규식 활용, ^는 공백문자가 아닌 문자를 의미하며 ^가 중간에 들어갈 경우 뒤에 오는 문자를 제외함

import re
lin = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008'
y = re.findall('@([^ ]*)', lin)
print(y)

#['uct.ac.za']

#조금 더 정교한 패턴 추출

import re
lin = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008'
y = re.findall('^From. *@([^ ]*)', lin)
print(y)

#['uct.ac.za']

 

종합 예제 : 패턴 추출 및 최댓값 찾기

import re
hand = open('mbox-short.txt')
numlist = list()
for line in hand:
    line = line.rstrip()
    stuff = re.findall('^X-DSPAM-Confidence: ([0-9.]+)', line)
    if len(stuff) !=1 : continue
    num = float(stuff[0])
    numlist.append(num)
print('Maximum:', max(numlist))

 

예외 문자(Escape Character)

특수문자로 이루어진 패턴을 찾기 위해 역슬래시(₩) 사용

import re
x = 'We just received $10.00 for cookies.'
y = re.findall('₩$[0-9.]+',x)
print(y)

#['$10.00']