• 파이썬은 정규 표현식을 지원하기 위해 re(regular expression) 모듈을 제공한다. re모듈은 파이썬을 설치할 때 자동으로 설치는 기본 라이브러리로 사용방법은 다음과 같다.
import re
p = re.compile('ab*')
  • re.compile을 사용하여 정규 표현식을 컴파일한다. re.compile의 결과로 돌려주는 객체 p를 사용하여 그 이후의 작업을 수행할 것이다.
    • 정규식을 컴파일할 때 특정 옵션을 주는 것도 가능한데 이에 대해서는 뒤에서 자세히 살펴본다
    • 패턴이란 정규식을 컴파일한 결과이다.
  • 정규식을 이용한 문자열 검색
    • 이제 컴파일된 패턴 객체를 사용하여 문자열 검색을 수행해보자. 컴파일된 패턴 객체는 다음과 같은 4가지 메서드를 제공한다.
      • match() : 문자열의 처음부터 정규식과 매치되는지 조사한다.
      • search() : 문자열 전체를 검색하여 정규식과 매치되는지 조사한다.
      • findall() : 정규식과 매치되는 모든 문자열을 리스트로 돌려준다.
      • finditer() : 정규식과 매치되는 모든 문자열을 반복 가능한 객체로 돌려준다.
    • match, search는 정규식과 매치될 때 match 객체를 돌려주고, 매치되지 않을 땐 None을 돌려준다. 이들 메서드에 대한 간단한 예를 들어보자
      • match 객체란 정규식의 검색 결과로 돌려주는 객체이다
    • 우선 다음과 같은 패턴을 만들어보자
import re
p = re.compile('[a-z]+')
  • match : match 메서드는 문자열의 처음부터 정규식과 매치되는지 조사한다. 위 패턴에 match 메서드를 수행해보자
m = p.match("python")
print(m)
m.group()
<re.Match object; span=(0, 6), match='python'>
'python'
  • "python" 문자열은 [a-z]+ 정규식에 부합되므로 match 객체를 돌려준다.
m = p.match("3 python")
print(m)
# m.group()
# None이라서 반환하지 못함
None
  • "3 python" 문자열은 처음에 나오는 문자 3이 [a-z]+에 부합되지 않으므로 None을 반환해준다.
  • match의 결과로 match객체 또는 None을 돌려주기 때문에 파이썬 정규식 프로그램은 보통 다음과 같은 흐름으로 작성한다.
p = re.compile(정규표현식)
m = p.match('string goes here')
if m:
    print('match found: ', m.group())
else : 
    print('No match')
  • if는 bool형을 읽는다. 즉, m이 뭔가 있단 얘기는 이를 True로 해석할 것이고 m이 None이 나오면 False와 진배 다를 바 없기 때문에 else로 넘어가서 수행할 것이다.
  • search : 컴파일된 패턴 객체 p를 가지고 이번에는 search 메서드를 수행해보자
m = p.search('python')
print(m)
<re.Match object; span=(0, 6), match='python'>
  • match 메서드와 동일하게 매치된다.
m = p.search('3 python')
print(m)
<re.Match object; span=(2, 8), match='python'>
  • '3 python' 문자열의 첫 번째 문자는 '3'이지만 search는 문자열의 처음부터 검색하는 것이 아니라 문자열 전체를 검색하기 때문에 '3' 이후의 'python' 문자열과 매치된다.
  • 이렇듯 match 메서드와 search 메서드는 문자열의 처음부터 검색할지의 여부에 따라 다르게 사용해야 한다.

  • findall
result = p.findall('life is too short')
print(result)
['life', 'is', 'too', 'short']
  • 'life is too short'문자열의 각 단어들을 각각 [a-z]+ 정규식과 매치해서 리스트로 돌려준다.

  • finditer
result = p.finditer("life is too short")
print(result)

for r in result: print(r)
<callable_iterator object at 0x000001E8A6348790>
<re.Match object; span=(0, 4), match='life'>
<re.Match object; span=(5, 7), match='is'>
<re.Match object; span=(8, 11), match='too'>
<re.Match object; span=(12, 17), match='short'>
  • finditer는 findall과 동일하지만 그 결과를 이용하여 반복 가능한 객체(iterator object)로 돌려준다. 반복 가능한 객체가 포함하는 각각의 요소는 match 객체이다.
  • match 객체의 메서드 : match 메서드와 search 메서드를 수행한 결과로 돌려준 match 객체에 대해 알아보자. 앞에서 정규식을 사용한 문자열 검색을 수행하면서 아마도 다음과 같은 궁금증이 생겼을 것이다.
  • 왜냐면 반환해준 결과가 알아먹기 힘들게 나왔기 때문이다
    • 어떤 문자열이 매치 되었는가?
    • 매치된 문자열의 인덱스는 어디서부터 어디까지인가?
  • match객체의 메서드를 사용하면 이 같은 궁금증을 해결할 수 있다.
    • group() : 매치된 문자열을 돌려준다.
    • start() : 매치된 문자열의 시작 위치를 돌려준다.
    • end() : 매치된 문자열의 끝 위치를 돌려준다.
    • span() : 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다.
    • 예를 들어 확인해보자
m = p.match("python")
print(m.group())
print(m.start())
print(m.end())
print(m.span())
python
0
6
(0, 6)
  • match 객체의 start()의 결과값은 항상 0일 수 밖에 없다
  • search도 확인해보자
m = p.search("3 python")
print(m.group())
print(m.start())
print(m.end())
print(m.span())
python
2
8
(2, 8)
  • 모듈 단위로 수행하기
    • 지금까지 우리는 re.compile을 사용하여 컴파일된 패턴 객체로 그 이후의 작업을 수행했다. re 모듈은 이것을 좀 축약한 형태로 사용할 수 있는 방법을 제공한다.
      p = re.compile('[a-z]+')
      m = p.match("python")
      
    • 이렇게 사용했다면
      m = re.match('[a-z]+', "python")
      
    • 이처럼 사용하면 컴파일과 match 메서드를 한 번에 수행할 수 있다.
    • 보통 한 번 만든 패턴 객체를 여러번 사용할 때는 이 방법보다 첫 번째 방법이 유용할 때가 있다.
  • 컴파일 옵션은 다음시간