본문 바로가기
자연어 처리

[딥러닝을 이용한 자연어 처리 입문] 정규 표현식

by 나연하야 2023. 2. 25.
  • 텍스트를 전처리하는 과정에서 '과정중심평가', '과정 중심 평가', '과정중심 평가'와 같은 동일한 의미를 가지지만 띄어쓰기가 다르게 된 단어들을 '과정중심평가'로 통일할 필요가 있음.
  • 이때, 모든 단어들을 각각 '과정중심평가'로 바꿀 수도 있지만 정규표현식을 사용하여 좀 더 간단하게 바꿀 수도 있음.
  • 그럼 파이썬에서 지원하고 있는 정규 표현식 모듈 re의 사용 방법에 대해서 알아보자.

 

1. re 모듈함수

  • 정규 표현식 re 모듈에서 지원하는 함수는 아래의 표와 같음.
  • 앞으로 진행될 실습에서는 re.compile()에 정규 표현식을 컴파일하고, re.search()를 통해서 해당 정규 표현식이 입력 텍스트와 매치되는지 확인해 볼 예정임.
  • re.search()는 매치된다면 Match Object를 리턴하고, 매치되지 않으면 아무런 값도 출력되지 않음.
모듈함수 의미
re.compile() 정규표현식을 컴파일하는 함수(파이썬에게 정규표현식을 전달하는 역할)
re.search() 문자열 전체에서 정규표현식과 매치되는지 검색
re.match() 첫 문자열이 정규표현식과 매치되는지 검색
re.split() 정규표현식을 기준으로 문자열 분리
re.findall() 정규표현식과 매치되는 문자열을 찾아 리턴
re.finditer() 정규표현식과 매치되는 문자열에 대한 이터레이터 객체를 찾아 리턴
re.sub() 정규표현식과 일치하는 부분을 다른 문자열로 대체

 

  • search()와 match()의 차이점은 search()의 경우 문자열 전체에서 정규 표현식과 매치되는지 확인하며, match()는 첫 문자열이 정규표현식과 매치되는지 확인함.
  • 아래의 예시에서 ab를 컴파일한 후, search()를 통해 kkab와 매치되는지 확인하면 Match Object이 리턴되고, match()를 통해서는 kkab와 매치되지 않고 ab가 문자열에 처음에 나오는 abkk와는 매치됨. 
import re
r=re.compile("ab")
r.search("kkab")
<re.Match object; span=(2, 4), match='ab'>
r=re.compile("ab")
r.match("kkab") # 아무런 결과도 출력되지 않음
r=re.compile("ab")
r.match("abkk")
<re.Match object; span=(0, 2), match='ab'>

 

  • split()을 통해 문자열들을 분리하여 리스트로 리턴받을 수 있음.
text="사과+딸기+수박+banana+^^"
re.split("\+", text)
['사과', '딸기', '수박', 'banana', '^^']

 

  • sub(A,B,C)는 C에서 A와 일치하는 것을 B로 대체하라는 의미임.
  • 아래의 예시는 text에서 소문자와 대문자를 제외하고 모두 띄어쓰기로 바꾸라는 의미로, 숫자가 띄어쓰기로 바뀐 것을 확인할 수 있음.
text="I am 28 years old."
text_re=re.sub("[^a-zA-Z]", " ", text)
print(text_re)
I am    years old

 

2. 정규 표현식

  • 자주 활용되는 정규표현식은 아래의 표와 같음.
정규표현식 의미
. 한 개의 임의의 문자
? 앞의 문자가 존재할 수도 있고, 존재하지 않을 수도 있음
* 앞의 문자가 무한개로 존재할 수도 있고, 존재하지 않을 수도 있음
+ 앞의 문자가 최소 1개 이상 존재함
^ 뒤의 문자열로 문자열이 시작
$ 앞의 문자열로 문자열이 마침
{숫자} 숫자만큼 반복
{숫자1, 숫자2} 숫자1이상 숫자2이하만큼 반복
{숫자,} 숫자 이상만큼 반복
[   ] 대괄호 안의 문자들 중 한 개의 문자와 매치
[^문자] 해당 문자를 제외한 문자를 매치
문자1|문자2 문자1 또는 문자2를 의미

 

  • .은 한 개의 임의의 문자를 나타내기 때문에 a.c는 abc와 매치되어 Match Object를 리턴, abbc와는 매치되지 않아 아무값도 출력하지 않음.
r=re.compile("a.c")
r.search("abc")
<re.Match object; span=(0, 3), match='abc'>
r=re.compile("a.c")
r.search("abbc") # 아무런 결과도 출력되지 않음

 

  • ?은 앞의 문자가 존재할 수도 있고 존재하지 않을 수도 있는 경우를 나타내기 떄문에 ab?c는 abc, ac와 매치되어 Match Object를 리턴, abbc와는 매치되지 않아 아무값도 출력하지 않음.
r=re.compile("ab?c")
r.search("abc")
<re.Match object; span=(0, 3), match='abc'>
r=re.compile("ab?c")
r.search("ac")
<re.Match object; span=(0, 2), match='ac'>
r=re.compile("ab?c")
r.search("abbc") # 아무런 결과도 출력되지 않음

 

  • {숫자}는 앞의 문자를 숫자만큼 반복한 것을 나타내기 떄문에 ab{2}c는 abbc와 매치되어 Match Object를 리턴, abc와는 매치되지 않아 아무값도 출력하지 않음.
r=re.compile("ab{2}c")
r.search("abbc")
<re.Match object; span=(0, 4), match='abbc'>
r=re.compile("ab{2}c")
r.search("abc") # 아무런 결과도 출력되지 않음

 

  • [   ]는 안에 있는 한 개의 문자와 매치되기 떄문에 [a-z]는 abc와 매치되어 Match Object를 리턴, AB1와는 매치되지 않아 아무값도 출력하지 않음.
r=re.compile("[a-z]")
r.search("abc")
<re.Match object; span=(0, 1), match='a'>
r=re.compile("[a-z]")
r.search("AB1") # 아무런 결과도 출력되지 않음

 

  • [^문자]는 ^기호 뒤에 있는 문자들을 제외한 모든 문자와 매치되기 떄문에 [^a-z]는 AB1와 매치되어 Match Object를 리턴, abc와는 매치되지 않아 아무값도 출력하지 않음.
r=re.compile("[^a-z]")
r.search("AB1")
<re.Match object; span=(0, 1), match='A'>
r=re.compile("[^a-z]")
r.search("abc") # 아무런 결과도 출력되지 않음

 

  • 역 슬래쉬(\)를 활용한 정규표현식도 자주 쓰이며, 아래와 같음.
정규표현식 의미
\\\\ 역 슬래쉬 문자 자체를 의미
\\d 모든 숫자를 의미, [0-9]와 동일한 의미
\\D 숫자를 제외한 모든 문자를 의미, [^0-9]와 동일한 의미
\\s 공백을 의미, [ \t\n\r\f\v]와 동일한 의미
\\S 공백을 제외한 문자를 의미, [^ \t\n\r\f\v]와 동일한 의미
\\w 문자 또는 숫자를 의미, [a-zA-Z0-9]와 동일한 의미
\\W 문자 또는 숫자가 아닌 문자를 의미, [^a-zA-Z0-9]와 동일한 의미

 

3. 그 외 정규 표현식

  • \s+는 공백을 찾아내는 정규식임.
text="I am 28 years old."
re.split("\s+", text)
['I', 'am', '28', 'years', 'old.']

 

  • \d+는 숫자를 찾아내는 정규식임.
re.findall("\d+", text)
['28']

 

  • [a-z]+는 소문자로 시작하는 패턴을 찾아내는 정규식임.
re.findall("[a-z]+", text)
['am', 'years', 'old']

 

출처: 유원준/안상준, 딥러닝을 이용한 자연어 처리 입문-1권, p73-p84.