3 분 소요


정규 표현식

re: 정규 표현식, regular expression, 텍스트 처리

In [1]:
import re 

기호 .

.의 갯수만큼의 문자

In [2]:
r = re.compile("a.c")
In [3]:
print(r.search("qwerty"))
Out [3]:
None

In [4]:
# r = re.compile("a.c")
print(r.search("abc"))
Out [4]:
<re.Match object; span=(0, 3), match='abc'>

In [5]:
print(r.search("abbc"))
Out [5]:
None

In [6]:
print(r.search("axc"))
Out [6]:
<re.Match object; span=(0, 3), match='axc'>

In [7]:
r2 = re.compile("a..c")
r2.search("abbc")
Out [7]:
<re.Match object; span=(0, 4), match='abbc'>

기호 ?

기호 앞의 문자가 0개 이거나 1개 이거나

In [8]:
r = re.compile("ab?c") # a와 c사이에 b가 와야함
In [9]:
print(r.search("abc"))
Out [9]:
<re.Match object; span=(0, 3), match='abc'>

In [10]:
print(r.search("abbc"))
Out [10]:
None

In [11]:
print(r.search("axc"))
Out [11]:
None

In [12]:
print(r.search("ac"))
Out [12]:
<re.Match object; span=(0, 2), match='ac'>

기호 *

기호 앞의 문자가 1개 이상

In [13]:
r = re.compile("ab*c")
In [14]:
print(r.search("a"))
Out [14]:
None

In [15]:
print(r.search("ac"))
Out [15]:
<re.Match object; span=(0, 2), match='ac'>

In [16]:
print(r.search("abc"))
Out [16]:
<re.Match object; span=(0, 3), match='abc'>

In [17]:
print(r.search("abbc"))
Out [17]:
<re.Match object; span=(0, 4), match='abbc'>

기호 +

기호 앞의 문자가 1개 이상

In [18]:
r = re.compile("ab+c")
In [19]:
print(r.search("ac"))
Out [19]:
None

In [20]:
print(r.search("abc"))
Out [20]:
<re.Match object; span=(0, 3), match='abc'>

In [21]:
print(r.search("abbc"))
Out [21]:
<re.Match object; span=(0, 4), match='abbc'>

기호 ^

기호 뒤의 문자로 시작

In [22]:
r = re.compile("^ab")
In [23]:
print(r.search("ab"))
Out [23]:
<re.Match object; span=(0, 2), match='ab'>

In [24]:
print(r.search("aab"))
Out [24]:
None

In [25]:
print(r.search("abc"))
Out [25]:
<re.Match object; span=(0, 2), match='ab'>

기호 {숫자}

기호 앞의 문자가 숫자 만큼 반복

In [26]:
r = re.compile("ab{2}c")
In [27]:
print(r.search("abc"))
Out [27]:
None

In [28]:
print(r.search("abbc"))
Out [28]:
<re.Match object; span=(0, 4), match='abbc'>

기호 {숫자1, 숫자2}

기호 앞의 문자가 숫자1 ~ 숫자2까지 반복

In [29]:
r = re.compile("ab{2,4}c")
In [30]:
print(r.search("abc"))
Out [30]:
None

In [31]:
print(r.search("abbc"))
Out [31]:
<re.Match object; span=(0, 4), match='abbc'>

In [32]:
print(r.search("abbbc"))
Out [32]:
<re.Match object; span=(0, 5), match='abbbc'>

In [33]:
print(r.search("abbbbc"))
Out [33]:
<re.Match object; span=(0, 6), match='abbbbc'>

In [34]:
print(r.search("abbbbbc"))
Out [34]:
None

기호 {숫자, }

기호 앞의 문자가 숫자이상 반복

In [35]:
r = re.compile("ab{2,}c")
In [36]:
print(r.search("abc"))
Out [36]:
None

In [37]:
print(r.search("abbc"))
Out [37]:
<re.Match object; span=(0, 4), match='abbc'>

In [38]:
print(r.search("abbbc"))
Out [38]:
<re.Match object; span=(0, 5), match='abbbc'>

In [39]:
print(r.search("abbbbc"))
Out [39]:
<re.Match object; span=(0, 6), match='abbbbc'>

In [40]:
print(r.search("abbbbbc"))
Out [40]:
<re.Match object; span=(0, 7), match='abbbbbc'>

기호 [ - ]

문자의 범위 앞-뒤 까지 순서대로 하나 찾음

In [41]:
r = re.compile("[b-e]")
In [42]:
print(r.search("abcdefghi"))
Out [42]:
<re.Match object; span=(1, 2), match='b'>

In [43]:
print(r.search("defghijklmn"))
Out [43]:
<re.Match object; span=(0, 1), match='d'>

In [44]:
print(r.search("efghijklmn"))
Out [44]:
<re.Match object; span=(0, 1), match='e'>

In [45]:
print(r.search("fghijklmn"))
Out [45]:
None

기호 [^ ]

뒤의 문자를 제외하고 하나 찾음

In [46]:
r = re.compile("[^abcd]")
In [47]:
print(r.search("a"))
Out [47]:
None

In [48]:
print(r.search("abc"))
Out [48]:
None

In [49]:
print(r.search("bcd"))
Out [49]:
None

In [50]:
print(r.search("abcde"))
Out [50]:
<re.Match object; span=(4, 5), match='e'>

In [51]:
print(r.search("efg"))
Out [51]:
<re.Match object; span=(0, 1), match='e'>

re.match vs re.search

In [52]:
r = re.compile("ab.")
In [53]:
print(r.match("tttabc")) # match: 처음부터 조사
Out [53]:
None

In [54]:
print(r.match("abcttt"))
Out [54]:
<re.Match object; span=(0, 3), match='abc'>

In [55]:
print(r.search("tttabc"))# search: 텍스트 전체를 보고 정규식(compile) 조사
Out [55]:
<re.Match object; span=(3, 6), match='abc'>

텍스트 분해

In [56]:
text = "자, 이제 match 메서드와 search 메서드를 수행한 결과로 리턴된 match 객체에 대해 알아보자. 앞에서 정규식을 사용한 문자열 검색을 수행하면서 아마도 다음과 같은 궁금증이 생겼을 것이다."
In [57]:
# 파이썬 내장 함수 split
text.split()
Out [57]:
['자,',
 '이제',
 'match',
 '메서드와',
 'search',
 '메서드를',
 '수행한',
 '결과로',
 '리턴된',
 'match',
 '객체에',
 '대해',
 '알아보자.',
 '앞에서',
 '정규식을',
 '사용한',
 '문자열',
 '검색을',
 '수행하면서',
 '아마도',
 '다음과',
 '같은',
 '궁금증이',
 '생겼을',
 '것이다.']
In [58]:
# re split 함수: 간단한 상수 문자열 일치로는 충분하지 않은 경우를 위해 설계
re.split(" ", text)
Out [58]:
['자,',
 '이제',
 'match',
 '메서드와',
 'search',
 '메서드를',
 '수행한',
 '결과로',
 '리턴된',
 'match',
 '객체에',
 '대해',
 '알아보자.',
 '앞에서',
 '정규식을',
 '사용한',
 '문자열',
 '검색을',
 '수행하면서',
 '아마도',
 '다음과',
 '같은',
 '궁금증이',
 '생겼을',
 '것이다.']
In [59]:
text2 = "안녕 나는+파이썬이야"
re.split("\+", text2)
Out [59]:
['안녕 나는', '파이썬이야']
In [60]:
text2.split("+")
Out [60]:
['안녕 나는', '파이썬이야']
In [61]:
text3 = '''
이름:Luke Skywarker
전화번호: 02-123-4567
이메일:luke@daum.net
성별:남자
'''
re.findall("\d+", text3) # \d: 숫자
Out [61]:
['02', '123', '4567']
In [62]:
text4 = '''“이온빔을 HfO2 기반 강유전체에 조사해 산소 공공을 형성했다”며 “기존의 복잡한 공정과 후처리 과정 없이 이온빔 조사밀도 조절만으로 강유전성을 200% 이상 강화했다”'''
re_res = re.sub("[^a-zA-Z]", ' ', text4) # 대소문자를 제외하고 ' '(공백)으로 치환
re_res
Out [62]:
'      HfO                                                                                      '
In [63]:
re_res.split()
Out [63]:
['HfO']
In [64]:
text5 = "ㅋㅋㅋ so 이따가 시간 돼?ㅠㅠ"
re.compile("[ 가-힣]+").sub("", text5) # 가-힝: 완성형 한글 전체 범위
Out [64]:
'ㅋㅋㅋso?ㅠㅠ'
In [65]:
re.compile("[가-힣]+").findall(text5)
Out [65]:
['이따가', '시간', '돼']
In [66]:
re.compile("[가-힣]+").sub("", text5).split()
Out [66]:
['ㅋㅋㅋ', 'so', '?ㅠㅠ']

s.split() vs. re.split(s)

In [67]:
import re, time, random 

def random_string(_len):
    letters = "ABC"
    return "".join([letters[random.randint(0,len(letters)-1)] for i in range(_len) ])

r = random_string(2000000)
pattern = re.compile(r"A")

start = time.time()
# pattern.split(r)
re.split(pattern, r)
print("re.split : ", time.time() - start)

start = time.time()
r.split("A")
print("내장 split : ", time.time() - start)
Out [67]:
re.split :  0.06091761589050293
내장 split :  0.03753256797790527

In [68]:
s = "One:two::t h r e e:::fourth field"
print(re.split(':+', s))
print(s.split(':'))

s = "One:two:2:t h r e e:3::fourth field"
print(re.split('[:\d]+',"One:two:2:t h r e e:3::fourth field"))
Out [68]:
['One', 'two', 't h r e e', 'fourth field']
['One', 'two', '', 't h r e e', '', '', 'fourth field']
['One', 'two', 't h r e e', 'fourth field']

내장 split은 추가로 작업이 더 필요하다

ex

In [69]:
search_target = '''Luke Skywarker 021234567 luke@daum.net
다스베이더 070-9999-9999 darth_vader@gmail.com
princess leia 010 2454 3457 leia@gmail.com'''
In [70]:
regex = r'0\d{1,2}[ -]?\d{3,4}[ -]?\d{3,4}' 
In [71]:
result = re.findall(regex, search_target)
print("\n".join(result))
Out [71]:
021234567
070-9999-9999
010 2454 3457

Reference

태그: ,

카테고리:

업데이트:

댓글남기기