정규식 따라잡기

6 분 소요

정규식 (Regular expression)

정규식은 텍스트에서 특정 글자나 단어, 패턴 등을 정확하고 유동적으로 표현하는 식이다. 이는 파이썬과는 관계 없는, 하나의 독립된 언어이다.

정규식: 문자열 비교나 처리를 위한 와일드 카드 표현식!

정규식 Cheat Sheet

기호 설명
^ 라인 첫번째에서만
$ 라인 마지막에서만
. 아무 문자나 ‘1 개’ (숫자안됨)
\s 공백
\S 공백아닌것
* 바로 앞 글자 반복(0개 포함)
*? 바로 앞 글자 반복(0개포함) (Non-greedy)
+ 바로 앞 글자 반복(1개부터)
+? 바로 앞 글자 반복(1개부터) (Non-greedy)
[AEIOU] []안에 있는 글자 중 ‘1 개’
[\^XYZ] []안에 없는 글자 중 ‘1 개’
[a-z0-9] range안에 있는 글자 중 ‘1 개’
( 추출대상 시작할 때
) 추출대상 끝날 때

예 시

파이썬에서 정규식을 사용하려면, 먼저 정규식 모듈 임포트를 해야 한다. import re를 사용.

기존 파이썬의 find() 메소드와 비슷하게 사용할 수 있다.

아래와 같은 txt파일이 있다고 해보자.

From stephen.marquard@uct.ac.za Sat Jan  5 09:14:16 
Return-Path: <postmaster@collab.sakaiproject.org>
From: stephen.marquard@uct.ac.za
Subject: [sakai] svn commit: r39772 

여기서 from:으로 시작하는 줄을 추출하고 싶다면?

기존의 find() 메소드

hand = open('mbox-short.txt')
 # for loop을 txt파일에 대해 실행하면 한 줄씩 들어간다. 
for line in hand:
	line = line.rstrip() # string 끝부분 공백 제거 
	# find() 는 결과가 없을 때 -1을 반환함 
	if line.find('From:') >= 0:
		print(line)

re.search() 메소드: True/False로 리턴함.

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

특수문자를 사용해 원하는 결과값 추출하기

아래와 같은 텍스트에서

X-Sieve: CMU Sieve 2.3
X-DSPAM-Result: Innocent
X-Plane is behind schedule: two weeks
X-: Very short
  • X부터 :까지 추출하고 싶다? X.*:라고 쓰면 됨. X로 시작하고, .이 여러 개 (*)있고 마지막에 :로 끝난다는 뜻.

  • X가 반드시 맨 앞에 와야만 한다? ^X.*:

  • 중간에 공백이 있으면 안된다? ^X\S+: . \S는 공백이 아닌 글자를 뜻한다. +*과 얼핏 비슷하지만 최소 1개는 있어야 한다는 뜻이다. 따라서 이 경우에는 ‘X:’ 와 같은 것은 추출되지 않는다.

re.findall()

re.search()와 if를 조합할 필요 없이, 있으면 그 문자열을 바로 출력해 주는 re.findall()을 사용해 보자.

[]중괄호는 range를 사용할 수 이다. 0부터 9 까지 숫자가 1개이상(+) 있는 경우, A,E,I,O,U 중 하나 이상 있는 경우. 만약 못 찾으면 false가 아닌 빈 list를 반환함에 주의.

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

Greedy 정규식.

정규식은 matching이 되면 최대한 길게 결과를 출력한다.

>>> 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'
>>> 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'
>>> y = re.findall('^From (\S+@\S+)', x)
>>> print(y)
['stephen.marquard@uct.ac.za']

응용편

메일 주소 중 도메인만 출력해 보자.

>>> import re
>>> x = 'From stephen.marquard@uct.ac.za Sat Jan'
>>> y = re.findall('^From @([^ ]*)', x)
>>> print(y)
['uct.ac.za']

해설

기호
^From 시작은 From이어야 함 (IF문 같은 것)
’ ‘ From과 @ 사이에 공백 있어야 하고
.* 아무 글자든지간에 (.) 0개이상 있어야(* )
@ @로 시작해야하고
( ) 여기만 출력할거야
[ ] 이 안에 있는 1글짜씩인 놈들인데
^ 공백이 아닌 거 (원래 ^는 맨 첫줄인데 뭐 NOT의 의미도 있나봄)
* 조건을 만족하는 한 끝까지 가자 (Greedy)

이런 느낌이다.

이스케잎 문자

만약 string중에서 $ 로 시작하는 부분을 추출하려면 어떻게 해야 하나? $는 라인 마지막에서만 찾으라는 뜻인데. 이럴 떄는 \ (백슬래쉬)를 사용하면 된다.

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

댓글남기기