2021. 4. 22. 16:16ㆍPYTHON/Do it! 점프 투 파이썬
07장 정규 표현식
07-1 정규 표현식 살펴보기
정규표현식(Regular Expressions)은 복잡한 문자열을 처리할 때 사용하는 기법으로 파이썬만의 고유 문법이 아니라 문자열을 처리하는 모든 곳에서 사용한다.
정규표현식은 왜 필요한가?
정규표현식을 사용하면 코드가 간결해진다.
import re
data="""
park 800905-1049118
kim 700905-1059119
"""
pat=re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))
park 800905-*******
kim 700905-*******
07-2 정규 표현식 시작하기
정규 표현식의 기초, 메타 문자
메타문자(meta characters)란 원래 그 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자이다.(.^$*+?{}[]/\())
문자 클래스 []
문자 클래스로 만들어진 정규식은 '[] 사이의 문자들과 매치'라는 의미를 갖는다. [] 안의 두 문자 사이에 하이픈(-)을 사용하면 두 문자 사이의 범위(From-To)를 의미한다. 문자 클래스[] 안에는 어떤 문자나 메타 문자도 사용할 수 있다. 문자 클래스 안에 ^메타 문자를 사용할 경우에는 반대(not)라는 의미를 갖는다.
*자주 사용하는 문자 클래스
\d: 숫자와 매치, [0-9]와 동일한 표현식이다.
\D: 숫자가 아닌 것과 매치, [^0-9]와 동일한 표현식이다.
\s: whitespace 문자(space나 tab처럼 공백을 표현하는 문자)와 매치, [ \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(.)
정규 표현식의 Dot(.) 메타 문자는 줄바꿈 문자인 \n을 제외한 모든 문자와 매치됨을 의미한다.
a.b = a+모든문자+b
a와 b라는 문자 사이에 어떤 문자가 들어가도 모두 매치된다는 의미이다.
a[.]b = a+Dot(.)문자+b
a.b문자열과만 매치된다.
반복(*)
메타문자 * 바로 앞에 있는 문자가 0부터 무한대로 반복될 수 있다는 의미이다.
ca*t
반복(+)
+는 최소 1번 이상 반복될 때 사용한다.
ca+t = c+a(1번 이상 반복)+t
반복({m,n}, ?)
{}메타문자를 사용하면 반복 횟수를 고정할 수 있다. {m,n} 정규식을 사용하면 반복 횟수를 m부터 n까지 매치할 수 있다. m또는 n을 생략할 수도 있다. 생략된 m은 0과 동일하며 생략된 n은 무한대(2억 개 미만)의 의미를 갖는다.
1. {m}
ca{2}t = c+a(반드시 두 번 반복)+t
2. {m,n}
ca{2,5}t = c+a(2~5번 반복)+t
3. ?
?메타문자가 의미하는 것은 {0,1}이다.
ab?c = a+b(있어도 되고 없어도 된다)+c
파이썬에서 정규 표현식을 지원하는 re(regular expression) 모듈
import re
p=re.compile('ab*')
re.compile의 결과로 돌려주는 객체 p(컴파일된 패턴 객체)를 사용하여 이후의 작업을 수행할 것이다.
정규식을 사용한 문자열 검색
컴파일된 패턴 객체를 사용하여 문자열 검색을 수행할 수 있다. 컴파일된 패턴 객체는 다음과 같은 4가지 메서드를 제공한다.
▷match(): 문자열의 처음부터 정규식과 매치되는지 조사한다.
▷search(): 문자열 전체를 검색하여 정규식과 매치되는지 조사한다.
▷findall(): 정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려준다.
▷finditer(): 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려준다.
match, search는 정규식과 매치될 때는 match 객체를 돌려주고 매치되지 않을 때는 none을 돌려준다.
import re
p=re.compile('[a-z]+')
match
m=p.match("python")
print(m)
<re.Match object; span=(0,6), match='python'>
"python"문자열은 [a-z]+ 정규식에 부함되므로 match 객체를 돌려준다.
m=p.match("3 python")
print(m)
None
"3 python"문자열은 처음에 나오는 문자 3이 정규식 [a-z]+에 부합되지 않으므로 None을 돌려준다.
match의 결과로 match객체 또는 None을 돌려주기 때문에 파이썬 정규식 프로그램은 보통 다음과 같은 흐름으로 작성한다. 즉 match의 결과값이 있을 때만 그 다음 작업을 수행하겠다는 것이다.
p=re.compile(정규 표현식)
m=p.match("조사할 문자열")
if m:
print('Match found: ', m.group())
else:
print('No match')
search
m=p.search("python")
print(m)
<re.Match object; span=(0,6), match='python'>
"python" 문자열에 search 메서드를 수행하면 match 메서드를 수행했을 때와 동일하게 매치된다.
m=p.search("3 python")
print(m)
<re.Match object; span(2,8), match='python'>
"3 python" 문자열의 첫 번째 문자는 "3"이지만 search는 문자열의 처음부터 검색하는 것이 아니라 문자열 전체를 검색하기 때문에 "3" 이후의 "python"문자열과 매치된다.
findall
result=p.findall("life is too short")
print(result)
['life', 'is', 'too', 'short']
"life is too short" 문자열의 'life', 'is', 'too', 'short' 단어를 각각 [a-z]+ 정규식과 매치해서 리스트로 돌려준다.
finditer
result=p.finditer("life is too short")
print(result)
<callable_iterator object at 0x01F5E390>
for r in result: print(r)
<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 객체의 메서드
▷group(): 매치된 문자열을 돌려준다.
▷start(): 매치된 문자열의 시작 위치를 알려준다.
▷end(): 매치된 문자열의 끝 위치를 알려준다.
▷span(): 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다.
import re
p=re.compile('[a-z]+')
m=p.match("python")
m.group()
'python'
m.start()
0
m.end()
6
m.span()
(0,6)
match 메서드를 수행한 결과로 돌려준 match 객체의 star()의 결과값은 항상 0일 수밖에 없다. 왜냐하면 match메서드는 항상 문자열의 시작부터 조사하기 때문이다.
만약 search 메서드를 사용했다면 start() 값은 다음과 같이 다르게 나올 것이다.
m=p.search("3 python")
m.group()
'python'
m.start()
2
m.end(){
8
m.span()
(2,8)
컴파일 옵션
▷DOTALL(S): dot문자(.)가 줄바꿈 문자를 포함하여 모든 문자와 매치한다.
▷IGNORECASE(I): 대, 소문자에 관계 없이 매치한다.
▷MULTILINE(M): 여러 줄과 매치한다. (^,$메타문자의 사용과 관계가 있는 옵션이다.)
▷VERBOSE(X): verbose모드를 사용한다. (정규식을 보기 편하게 만들 수도 있고 주석 등을 사용할 수도 있다.)
옵션을 사용할 때는 re.DOTALL처럼 전체 옵션이름을 써도 되고 re.S처럼 약어를 써도 된다.
DOTALL, S
.메타문자는 줄바꿈 문자(\n)를 제외한 모든 문자와 매치되는 규칙이 있다. 만약 \n문자도 포함하여 매치하고 싶다면 re.DOTALL 또는 re.S 옵션을 사용해 정규식을 컴파일 하면 된다. 보통 re.DOTALL 옵션은 여러 줄로 이루어진 문자열에서 \n에 상관없이 검색할 때 많이 사용한다.
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)
<re.Match object; span=(0,3), match='a\nb'>
IGNORECASE, I
re.IGNORECASE 또는 re.I 옵션은 대,소문자 구별 없이 매치를 수행할 때 사용하는 옵션이다. [a-z]정규식은 소문자만을 의미하지만 re.I 옵션으로 대,소문자 구별 없이 매치된다.
p=re.compile('[a-z]', re.I)
p.match('python')
<re.Match object; span(0,1), match='p'>
p.match('Python')
<re.Match object; span(0,1), match='P'>
p.match('PYTHON')
<re.Match object; span(0,1), match='P'>
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이라는 문자열을 사용한 첫 번째 줄만 매치된 것이다.
^메타문자를 문자열 전체의 처음이 아니라 각 라인의 처음으로 인식시키고 싶은 경우 re.MULTILINE 또는 re.M 옵션을 사용할 수 있다.
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))
re.MULTILINE 옵션으로 인해 ^메타문자가 문자열 전체가 아닌 각 줄의 처음이라는 의미를 갖게되어 다음과 같은 결과가 출력된다. 즉 re.MULTILINE 옵션은 ^,$메타 문자를 문자열의 각 줄마다 적용해 주는 것이다.
['python one', 'python two', 'python three']
VERBOSE, X
re.VERBOSE 옵션을 사용하면 문자열에 사용된 whitespace는 컴파일할 때 제거된다. (단 []안에 사용한 whitespace는 제외) 그리고 줄 단위로 #기호를 사용하여 주석문을 작성할 수 있다.
(여기 나온 코드는 도저히 무슨 말인지 이해도 안 가고 복잡해서 따라 쓸 수조차 따라갈 수조차 없어서 생략한다...)
백슬래시 문제
정규식 문자열 앞에 r문자를 삽입하면 이 정규식은 Raw String 규칙에 의하여 백슬래시 2개 대신 1개만 써도 2개를 쓴 것과 동일한 의미를 갖게 된다.
p=re.compile('\\\\section')
p=re.compile(r'\\section')
하 도대체 무슨 말인지 1도 이해가 안 된다...
......
나는 무엇을 하는 걸까
뭘 하고 있는 거지
'PYTHON > Do it! 점프 투 파이썬' 카테고리의 다른 글
[Do it! 점프 투 파이썬-스터디 노트] 코딩 면허 시험 (0) | 2021.04.25 |
---|---|
[Do it! 점프 투 파이썬-스터디 노트] 07장 정규 표현식(07-3 강력한 정규 표현식의 세계로) (0) | 2021.04.23 |
[Do it! 점프 투 파이썬-스터디 노트] 06장 파이썬 프로그래밍, 어떻게 시작해야할까?(06-4~06-6) (0) | 2021.04.21 |
[Do it! 점프 투 파이썬-스터디 노트] 06장 파이썬 프로그래밍, 어떻게 시작해야할까?(06-1~06-3) (0) | 2021.04.21 |
[Do it! 점프 투 파이썬-스터디 노트] 05장 파이썬 날개 달기 연습문제 (0) | 2021.04.21 |