본문 바로가기
Python

정규표현식(regular expression)

by rubyda 2020. 8. 15.
728x90

정규표현식(regular expression)


정규표현식은 복잡한 문자열을 처리할 때 유용하게 사용하는 방법입니다. 특히 크롤링할때 굉장히 유용하게 사용이 됩니다.

정규표현식 모듈 (re)

파이썬에서는 정규 표현식을 지원하기 위해서 re 모듈을 제공하여 줍니다. re 모듈을 사용하면 특정 패턴과 일치하는 문자열을 검색, 치환, 제거 등을 할 수 있습니다.

raw string

r을 문자열 앞에 붙이면 문자열을 그대로 변환하여 줍니다.

 

In

a = 'abcdef\n'
print(a)
b = r'abcdef\n'
print(b)

Out

abcdef

abcdef\n

파이썬에서는 \n이 개행문자로 사용이 되는데 위와 같이 r을 써주면 문자 그대로 인식하게 됩니다.

 

정규표현식 메타 문자

정규표현식에서 사용하는 메타 문자들은 다음과 같은 것들이 있습니다.

. ^ $ * + ? { } [ ] \ | ( )

[] 문자 클래스


[]는 문자의 범위를 나타내기 위해서 사용이 됩니다. 예를 들어서 [a,b,c]라고 한다면 a,b,c중 한 개의 문자와 매치하겠다 라는 의미입니다.

  • [abcd] : a or b or c or d
  • [abc.^] : a or b or c or . or ^
  • [a-d] : -를 사용하면 두 문자 사이의 범위를 의미합니다. 즉 [a-d]는 a,b,c,d를 의미합니다.
  • [0-9] : 모든 숫자
  • [a-z] : 모든 소문자
  • [A-Z] : 모든 대문자
  • [a-zA-Z0-9] : 모든 알파벳 문자 및 숫자
  • [^0-9] : ^가 맨 앞에 사용 되는 경우 해당 문자 패턴이 아닌 것을 매칭 합니다.

search 

  • 첫번째로 패턴을 찾으면 match 객체를 반환합니다.
  • 패턴을 찾지 못하면 None을 반환합니다.

re 모듈에서 제공하는 search 함수를 통해서 예제를 연습해 보도록 하겠습니다.

 

In

a = re.search(r'[abcd]og', 'dog')
print(a)

Out

<re.Match object; span=(0, 3), match='dog'>

In

re.search(r'min[0-9]', 'min1')

Out

<re.Match object; span=(0, 4), match='min1'>

In

a = re.search(r'[abc.^]haha', 'ahaha')
print(a)
b = re.search(r'[abc.^]haha', '.haha')
print(b)
c = re.search(r'[abc.^]haha', '^haha')
print(c)
d = re.search(r'[abc.^]haha', 'dhaha')
print(d)

Out

<re.Match object; span=(0, 5), match='ahaha'>
<re.Match object; span=(0, 5), match='.haha'>
<re.Match object; span=(0, 5), match='^haha'>
None

 

자주 사용되는 문자 클래스


  • .  - 어떤 한개의 character와 일치 (newline(엔터) 제외)

  • \w - 문자+수자와 매치 [a-zA-Z0-9]

  • \s - 공백문자와 매치
  • \t, \n, \r - tab, newline, return
  • \d - 숫자 character와 매치 [0-9]
  • ^ = 시작, $ = 끝 각각 문자열의 시작과 끝을 의미합니다.
  • \가 붙으면 예를들어 \.는 .자체를 의미 \\는 \를 의미합니다.

 

\


1) 다른 문자와 함께 사용해서 특별한 의미를 가지게 해줍니다.

  • \d : 숫자 [0-9]와 의미가 같습니다.
  • \D : 숫자가 아닌 문자 [^0-9]와 의미가 같습니다.
  • \s : 공백 문자(띄어쓰기, 탭, 엔터 등)를 의미합니다.
  • \S : 공백이 아닌 문자를 의미합니다.
  • \w : 알파벳 대소문자, 숫자 [0-9a-zA-Z]와 이미가 같습니다.
  • \W : [^0-9a-zA-Z]와 의미가 동일합니다.

2) 메타 문자가 그 문자 자체로 표현하고 싶을때 사용됩니다.

  • \. , \\

In

a = re.search(r'\sand', 'cat and dog.')
print(a)

 

Out

<re.Match object; span=(3, 7), match=' and'>

In

a = re.search(r'\sand', 'cat land dog.')
print(a)

Out

None

In

a = re.search(r'\.dog', '.dog')
print(a)

Out

<re.Match object; span=(0, 4), match='.dog'>

 

 

.


모든 문자를 의미합니다.

 

In

a = re.search(r'd.g', 'dog')
print(a)
b = re.search(r'd.g', 'dig')
print(b)
c = re.search(r'd.g', 'd*g')
print(c)

Out

<re.Match object; span=(0, 3), match='dog'>
<re.Match object; span=(0, 3), match='dig'>
<re.Match object; span=(0, 3), match='d*g'>

 

반복패턴


특정한 패턴 뒤에 *, +, ? 이 오면 해당 패턴이 반복적으로 사용됬는지 체크하여 줍니다.

  • '+' : 1번 이상의 패턴
  • '*' -> 0번 이상의 패턴
  • '?' -> 0 또는 1번의 패턴

* 반복 패턴의 경우 greedy하게 체크를 합니다.(최대한 많은 부분이 일치하도록) 

ex) 1[123]*4 라는 패턴이 있을때 123421234의 경우 12, 1234, 123421234 다 가능하지만 가장 많은 부분이 일치하는  123421234를 검색하게 됩니다.

 

그루핑


그루핑은 ()을 사용합니다. 일치하는 결과를 그룹별로 분리하고 싶을때 사용합니다.

 

In

m = re.search(r'(\w+)@(.+)', 'minji@naver.com')
print(m.group(1))
print(m.group(2))

Out

minji
naver.com

다음과 같이 분리를 해주는데 인덱싱을 통해서 다음과 같이 출력할 수 있습니다.

 

{}


{}는 반복 횟수를 고정하게 해줍니다.

  • {5} - 5번 반복
  • {2,5} - 2 ~ 5번 반복

In

a = re.search('min{1,5}ji', 'minnnnnji')
print(a)
b = re.search('min{1,5}ji', 'minnnnnnji')
print(b)

Out

<re.Match object; span=(0, 9), match='minnnnnji'>
None

 

match


문자열의 처음부터 정규식과 매치되는지 조사하여 줍니다. search와 비슷하지만 주어진 문자열의 시작부터 비교하여 패턴이 있는지 조사합니다.

 

In

a = re.match(r'\d\d\d', 'number is 123')
print(a)

Out

None

In

a = re.match(r'\d\d\d', '123 is number')
print(a)

Out

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

 

findall()


정규식과 매치되는 모든 문자열을 리스트로 반환합니다. search가 처음으로 매칭되는 패턴만 반환을 한다면 findall은 전체를 반환하여 줍니다.

 

In

a = re.findall(r'[\w]+@[\w.]+', 'minj1@naver.com and siyeon@naver.com')
print(a)

Out

['minj1@naver.com', 'siyeon@naver.com']

 

sub()


주어진 문자열에서 매치된 문자를 다른 문자로 치환할때 사용합니다. 사용 방법은 다음과 같습니다.

re.sub('패턴', '바꾸고 싶은 문자 or 함수', '문자열')

 

In

a = re.sub(r'[\w]+@[\w.]+', 'hi', 'minj1@naver.com and siyeon@naver.com')
print(a)

Out

hi and hi

 

compile()


동일한 정규표현식을 매번 다시 쓰기 귀찮을때 유용하게 사용이 됩니다.

email = re.compile(r'[\w]+@[\w.]+')
email.search('minji@naver.com hi good')
<re.Match object; span=(0, 15), match='minji@naver.com'>