본문 바로가기

Python/점프 투 파이썬

[Regular Expression 정규표현식]

 [ ] 문자 클래스

[abc]

a, b, c 중 한 개의 문자와 매치

"a", "before", "dude"

=> 매치, 매치, 매치 안됨

 

[ ] 안의 두 문자 사이에 하이픈(-)을 사용하면 두 문자 사이의 범위(From - To)를 의미

[a-c] = [abc]

[0-5] = [012345]

 

  • [a-zA-Z] : 알파벳 모두
  • [0-9] : 숫자
  • [^0-9] : 숫자가 아닌 모든 문자
  •  
  • \d - 숫자와 매치, [0-9]와 동일
  • \D - 숫자가 아닌 것과 매치, [^0-9]와 동일.
  • \s - whitespace 문자와 매치, [ \t\n\r\f\v]와 동일. 맨 앞의 빈 칸은 공백문자(space)를 의미.
  • \S - whitespace 문자가 아닌 것과 매치, [^ \t\n\r\f\v]와 동일.
  • \w - 문자+숫자 (alphanumeric)와 매치, [a-zA-Z0-9_]와 동일.
  • \W - 문자+숫자 (alphanumeric)가 아닌 문자와 매치, [^a-zA-Z0-9_]와 동일.

대문자로 사용된 것은 소문자의 반대

 

. Dot

줄바꿈 문자인 \n을 제외한 모든 문자와 매치

(re.DOTALL 옵션을 주면 \n 문자와도 매치된다)

 

a.b

"a + 모든문자 + b"

a와 b라는 문자 사이에 어떤 문자가 들어가도 모두 매치

 

"aab", "a0b", "abc"

=> 매치, 매치, 매치 안됨

 

 

* 0 이상 반복 

ca*t

* 바로 앞에 있는 문자 a가 0부터 무한대로 반복될 수 있다는 의미

"ct", "cat","caaat"

=> 매치, 매치, 매치

 

 

+ 1 이상 반복 

ca+t

"ct", "cat","caaat"

=> 매치안됨, 매치, 매치

 

반복횟수 지정 ({m,n}, ?)

{m, n} 정규식을 사용하면 반복 횟수가 m부터 n까지 매치

m 또는 n을 생략 가능 (생략된 m은 0과 동일하며, 생략된 n은 무한대(2억 개 미만)의 의미)

 

{3,}

반복 횟수가 3 이상

{,3}

반복 횟수가 3 이하

 

ca{2,5}t

문자 a가 2~5번까지 반복될 수 있다

"ct", "caat","caaat"

=> 매치안됨, 매치, 매치

 

? 메타문자가 의미하는 것은 {0, 1}

ab?c

a + b(있어도 되고 없어도 된다) + c

"ac", "abc"

=> 매치, 매치

 

 

re 모듈

import re
p = re.compile('ab*')

re.compile을 사용하여 정규 표현식(위 예에서는 ab*)을 컴파일한다. re.compile의 결과로 돌려주는 객체 p(컴파일된 패턴 객체)를 사용하여 그 이후의 작업을 수행

 

 

컴파일된 패턴 객체가 제공하는 4가지 메서드

match() 문자열의 처음부터 정규식과 매치되는지 조사한다.
search() 문자열 전체를 검색하여 정규식과 매치되는지 조사한다.
findall() 정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려준다.
finditer() 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려준다.

match, search는 정규식과 매치될 때는 match 객체를 돌려주고, 매치되지 않을 때는 None을 돌려준다. (match 객체란 정규식의 검색 결과로 돌려주는 객체)

 

match()

import re
p = re.compile('[a-z]+')

m = p.match("python")
print(m)
# <_sre.SRE_Match object at 0x01F3F9F8>

m = p.match("3 python")
print(m)
# None

"python" 문자열은 [a-z]+ 정규식에 부합되므로 match 객체를 돌려준다.

"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')

search()

import re
p = re.compile('[a-z]+')

m = p.search("python")
print(m)
# <_sre.SRE_Match object at 0x01F3FA68>

m = p.search("3 python")
print(m)
# <_sre.SRE_Match object at 0x01F3FA30>

"python" 문자열에 search 메서드를 수행하면 match 메서드를 수행했을 때와 동일하게 매치

"3 python" 문자열의 첫 번째 문자는 "3"이지만 search는 문자열의 처음부터 검색하는 것이 아니라 문자열 전체를 검색하기 때문에 "3 " 이후의 "python" 문자열과 매치

 

findall()

import re
p = re.compile('[a-z]+')

result = p.findall("life is too short")
print(result)
# ['life', 'is', 'too', 'short']

"life is too short" 문자열의 'life', 'is', 'too', 'short' 단어를 각각 [a-z]+ 정규식과 매치해서 리스트로 돌려준다.

 

finditer()

import re
p = re.compile('[a-z]+')
result = p.finditer("life is too short")
print(result)
# <callable_iterator object at 0x01F5E390>

for r in result: print(r)
# ...
# <_sre.SRE_Match object at 0x01F3F9F8>
# <_sre.SRE_Match object at 0x01F3FAD8>
# <_sre.SRE_Match object at 0x01F3FAA0>
# <_sre.SRE_Match object at 0x01F3F9F8>

finditer는 findall과 동일하지만 그 결과로 반복 가능한 객체(iterator object)를 돌려준다. 반복 가능한 객체가 포함하는 각각의 요소는 match 객체

 

 

match 객체의 메서드

match 메서드와 search 메서드를 수행한 결과로 돌려준 match 객체

group() 매치된 문자열을 돌려준다.
start() 매치된 문자열의 시작 위치를 돌려준다.
end() 매치된 문자열의 끝 위치를 돌려준다.
span() 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다.
m = p.match("python")

m.group()
# 'python'
m.start()
# 0
m.end()
# 6
m.span()
# (0, 6)

m = p.search("3 python")
m.group()
# 'python'
m.start()
# 2
m.end()
# 8
m.span()
# (2, 8)

 

re.compile을 사용하여 컴파일된 패턴 객체로 그 이후의 작업을 수행할 수 있지만,

re 모듈은 이것을 좀 축약한 형태로도 사용할 수 있다.

p = re.compile('[a-z]+')
m = p.match("python")


m = re.match('[a-z]+', "python")

 

 

컴파일 옵션

  • DOTALL(S) - . 이 줄바꿈 문자를 포함하여 모든 문자와 매치할 수 있도록 한다.
  • IGNORECASE(I) - 대소문자에 관계없이 매치할 수 있도록 한다.
  • MULTILINE(M) - 여러줄과 매치할 수 있도록 한다. (^, $ 메타문자의 사용과 관계가 있는 옵션이다)
  • VERBOSE(X) - verbose 모드를 사용할 수 있도록 한다. (정규식을 보기 편하게 만들수 있고 주석등을 사용할 수 있게된다.)

옵션을 사용할 때는 re.DOTALL처럼 전체 옵션 이름을 써도 되고 re.S처럼 약어를 써도 된다.

 

 

DOTALL, S

. 메타 문자는 줄바꿈 문자(\n)를 제외한 모든 문자와 매치되는 규칙이 있다.

만약 \n 문자도 포함하여 매치하고 싶다면 re.DOTALL 또는 re.S 옵션을 사용해 정규식을 컴파일

import re
p = re.compile('a.b')
m = p.match('a\nb')
print(m) 
# None

p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m) 
# <_sre.SRE_Match object at 0x01FCF3D8>

정규식이 a.b인 경우 문자열 a\nb는 매치되지 않음을 알 수 있다. 왜냐하면 \n은 . 메타 문자와 매치되지 않기 때문이다. \n 문자와도 매치되게 하려면 다음과 같이 re.DOTALL 옵션을 사용해야 한다.

보통 re.DOTALL 옵션은 여러 줄로 이루어진 문자열에서 \n에 상관없이 검색할 때 많이 사용

 

IGNORECASE, I

re.IGNORECASE 또는 re.I 옵션은 대소문자 구별 없이 매치를 수행할 때 사용하는 옵션

p = re.compile('[a-z]', re.I)
p.match('python')
# <_sre.SRE_Match object at 0x01FCFA30>
p.match('Python')
# <_sre.SRE_Match object at 0x01FCFA68>
p.match('PYTHON')
# <_sre.SRE_Match object at 0x01FCF9F8>

[a-z] 정규식은 소문자만을 의미하지만 re.I 옵션으로 대소문자 구별 없이 매치

 

MULTILINE, M

re.MULTILINE 또는 re.M 옵션은 메타 문자인 ^, $와 연관된 옵션

^는 문자열의 처음

$는 문자열의 마지막

정규식이 ^python인 경우 문자열의 처음은 항상 python으로 시작해야 매치, 정규식이 python$이라면 문자열의 마지막은 항상 python으로 끝나야 매치

 

import re
p = re.compile("^python\s\w+")

data = """python one
life is too short
python two
you need python
python three"""

print(p.findall(data))
# ['python one']

^python\s\w+은 python이라는 문자열로 시작하고 그 뒤에 whitespace, 그 뒤에 단어가 와야 한다는 의미이다. 검색할 문자열 data는 여러 줄로 이루어져 있다.

^ 메타 문자에 의해 python이라는 문자열을 사용한 첫 번째 줄만 매치된 것이다.

하지만 ^ 메타 문자를 문자열 전체의 처음이 아니라 각 라인의 처음으로 인식시키고 싶은 경우

import re
p = re.compile("^python\s\w+", re.MULTILINE)

data = """python one
life is too short
python two
you need python
python three"""

print(p.findall(data))
# ['python one', 'python two', 'python three']

re.MULTILINE 옵션으로 인해 ^ 메타 문자가 문자열 전체가 아닌 각 줄의 처음이라는 의미를 갖게 되었다.

re.MULTILINE 옵션은 ^, $ 메타 문자를 문자열의 각 줄마다 적용해 주는 것

 

 


정규식에서 '\section' 문자열을 찾기 위해서는

import re
p = re.compile(r'\\section')

정규식 문자열 앞에 r 문자를 삽입하면 이 정규식은 Raw String 규칙에 의하여 백슬래시 2개 대신 1개만 써도 2개를 쓴 것과 동일한 의미

 

출처

wikidocs.net/4308