일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- 그리디
- test-helper
- Python
- 실전알고리즘
- Object detection
- ubuntu
- ssd
- docker
- 구현
- 코드수행
- STL
- 자료구조 및 실습
- 백준
- MySQL
- 1단계
- pytorch
- CS231n
- 모두를 위한 딥러닝 강좌 시즌1
- 3단계
- 이것이 코딩테스트다 with 파이썬
- 전산기초
- 프로그래머스
- 머신러닝
- C++
- SWEA
- 2단계
- 파이썬
- cs
- AWS
- 딥러닝
- Today
- Total
곰퓨타의 SW 이야기
[python] 정규 표현식 시작하기 뿌시기 본문
사실 정규 표현식을 사용할 일은 거의 없었다.
이번 학기 수업을 통해 풀스택으로 웹 프로젝트를 진행하였는데, 정규식을 사용하면 편할 것 같다는 생각을 종종하였었다.
정규 표현식은 외계어 같이 생겨서, 인터넷 검색을 하고 채워넣는 식으로 하였었다.
머신러닝에서 데이터 크롤링을 할 때에도 사용할 수 있을 것 같고, 앞으로 필요한 상황이 분명히 또 올것이라고 생각하기 때문에 점프투 파이썬 책을 차근차근 따라가면서 정리를 해놓고자 한다.
정규식은 정말 잘 몰라서 그대로 따라가보자 한다!!!
[내사랑 점프투 파이썬❣️]
위키독스
온라인 책을 제작 공유하는 플랫폼 서비스
wikidocs.net
정규 표현식의 기초, 메타 문자
정규 표현식에서 ' 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자'를 메타문자 라고 한다.
. ^ $ * + ? { } [ ] \ | ( )
이들은 특별한 의미를 갖는다 ~!
1. 문자 클래스 []
문자 클래스로 만들어진 정규식은 "[] 사이의 문자들과 매치" 라는 의미를 갖는다.
ex) [abc]라면, "a,b,c 중 한 개의 문자와 매치"라는 뜻을 갖는다.
- "a"는 정규식과 일치하는 문자인 "a"가 있으므로 매치
- "before"는 정규식과 일치하는 문자인 "b"가 있으므로 매치
- "dude"는 정규식과 일치하는 문자인 a, b, c 중 어느 하나도 포함하고 있지 않으므로 매치되지 않음
[]안의 두 문자 사이에서 - 를 사용하면 두 문자의 범위(From- To)를 의미한다.
ex. [a-c] = [abc], [0-5] = [012345]
[a-zA-Z] : 알파벳 모두
[0-9] : 숫자
[] 안에서 ^를 사용하면 not 의 의미를 갖는다. 예를 들어, [^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_]와 동일한 표현식이다.
대문자로 사용된 것은 소문자와 반대이다 !!
2. Dot (.)
'.' 은 \n을 제외한 모든 문자와 매치됨을 의미한다. (DOTALL 옵션을 주면 \n과도 매치된다.)
a.b
"a + 모든 문자 + b" : a와 b 문자 사이에 어떤 문자가 오더라도 매치된다.
ex ) 문자열 "aab", "a0b", "abc" -> a.b 매치
- "aab"는 가운데 문자 "a"가 모든 문자를 의미하는 .과 일치하므로 정규식과 매치된다.
- "a0b"는 가운데 문자 "0"가 모든 문자를 의미하는 .과 일치하므로 정규식과 매치된다.
- "abc"는 "a"문자와 "b"문자 사이에 어떤 문자라도 하나는있어야 하는 이 정규식과 일치하지 않으므로 매치되지 않는다.
a[.]b
"a + Dot(.)문자 + b"는 a와 b 사이에 '.' 문자가 있는 경우만 매치된다!
3. 반복 (*)
* 는 * 바로 앞에 있는 문자 a가 0개 이상으로 무한대로 반복할 수 있다. (메모리 제한으로 2억개 까지..ㅎㅎ)
ca*t
ca*t 정규식이 있는 경우,
ct yes "a"가 0번 반복되어 매치
cat yes "a"가 0번 이상 반복되어 매치
caaat yes "a"가 0번 이상 반복되어 매치
4. 반복 (+)
+는 *과 다르게 1번 이상 반복되면 매치된다.
ca+t
"c + a(1번 이상 반복) + t"
위의 정규식과 매치 여부
ct no "a"가 0번 나타나서 매치되지 않음
cat yes "a"가 1번 이상 반복되어 매치
caaat yes "a"가 1번 이상 반복되어 매치
5. 반복 ((m,n),?)
반복횟수를 지정하고 싶은 경우! -> {} 메타문자로 구현이 가능하다.
{m,n} 반복횟수가 m부터 n까지 매치가 가능하다.
{3, } : 3 이상인 경우
{,3} : 3 이하인 경우
1. {m}
ca{2}t
"c + a(반드시 2번 반복) + t"
2. {m,n}
ca{2,5}t
"c + a(2~5회 반복) + t"
3. ?
?는 {0,1}을 의미한다.
ab?c
" a+b(있어도 되고 없어도 된다) + c"
파이썬에서 정규 표현식을 지원하는 Re 모듈
>>> import re
>>> p = re.compile('ab*')
re.compile을 통해 정규 표현식을 컴파일한다. 컴파일된 객체인 p를 사용하여 그 이후의 작업을 수행할 것이다.
(패턴 : 정규식을 컴파일한 결과)
정규식을 이용한 문자열 검색
컴파일된 객체는 다음과 같은 4가지 메서드를 제공한다.
Method | 목적 |
match() | 문자열의 처음부터 정규식과 매치되는지 조사 |
search() | 문자열 전체를 검색하여 정규식과 매치되는지 조사 |
findall() | 정규식과 매치되는 모든 문자열(substring)을 리스트로 돌려줌 |
finditer() | 정규식과 매치되는 모든 문자열(substring)을 반복 가능한 객체로 돌려줌 |
match, search는 정규식과 매치될 때는 match 객체를 돌려주고,
매치되지 않을 때는 None을 돌려준다.
(match 객체 : 정규식의 검색 결과로 돌려주는 객체이다.)
패턴을 만들면 다음과 같다.
>>> import re
>>> p = re.compile('[a-z]+')
1. match
위의 패턴에 적용시킨 match 함수
>>> m = p.match("python") # 매치되는 것이 있는 경우
>>> print(m)
<_sre.SRE_Match object at 0x01F3F9F8>
>>> m = p.match("3 python") # 매치되는 것이 없는 경우
>>> print(m)
None
match의 흐름
p = re.compile(정규표현식)
m = p.match( 'string goes here' )
if m:
print('Match found: ', m.group())
else:
print('No match')
2. search
문자열 처음부터 검사하는 match와 다르게, 전체적으로 보고 매치되는 패턴이 있는지 확인하는 것이 search 이다❗️
>>> 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>
3. findall
정규식과 매치해서 리스트로 돌려준다.
>>> result = p.findall("life is too short")
>>> print(result)
['life', 'is', 'too', 'short']
4. finditer
findall과 동일하지만, 결과로 반복가능한 match 객체 형태로 돌려준다!
>>> 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>
match 객체의 메서드
아래와 같은 의문점을 해결하기 위해 여러 메서드를 제공한다.
- 어떤 문자열이 매치되었는가?
- 매치된 문자열의 인덱스는 어디서부터 어디까지인가?
method | 목적 |
group() | 매치된 문자열을 돌려준다. |
start() | 매치된 문자열의 시작 위치를 돌려준다. |
end() | 매치된 문자열의 끝 위치를 돌려준다. |
span() | 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려준다. |
match는 문자열 처음부터 검사하므로 start()의 결괏값은 항상 0일 수 밖에 없다.
>>> m = p.match("python")
>>> m.group()
'python'
>>> m.start()
0
>>> m.end()
6
>>> m.span()
(0, 6)
search를 사용하면 다음과 같다.
>>> m = p.search("3 python")
>>> m.group()
'python'
>>> m.start()
2
>>> m.end()
8
>>> m.span()
(2, 8)
[모듈 단위로 수행하기]
한 번 만든 패턴 객체를 여러번 사용해야 할 때는 아래의 방법보다 re.compile을 사용하는 것이 편하다.
>>> 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처럼 약어를 써도 된다.
1. DOTALL, S
'.' 메타 문자는 \n을 제외한 모든 문자와 매치되는 규칙이 있다. \n문자도 포함하고 싶은 경우 re.DOTALL, re.S 옵션을 사용하여 정규식을 컴파일하면 된다.
이는 여러 줄로 이루어진 문자열에서 \n에 상관없이 검색할 때 많이 사용된다.
>>> import re
>>> p = re.compile('a.b') # . 사용한 경우
>>> m = p.match('a\nb')
>>> print(m)
None
>>> p = re.compile('a.b', re.DOTALL) # DOTALL 옵션을 사용한 경우
>>> m = p.match('a\nb')
>>> print(m)
<_sre.SRE_Match object at 0x01FCF3D8>
2. IGNORECASE, I
re.IGNORECASE 또는 re.I 옵션은 대소문자 구별 없이 매치를 수행할 때 사용하는 옵션이다.
>>> p = re.compile('[a-z]', re.I) # [a-z]는 소문자, but 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>
3. MULTILINE, M
re.MULTILINE 또는 re.M 옵션은 메타 문자인 ^, $와 연관된 옵션이다.
^는 문자열 처음을 의미하고, $는 문자열의 마지막을 의미한다.
^python : 항상 Python으로 시작해야 매치된다.
python$ : 항상 python으로 끝나야 매치된다.
^python\s\w+은 python 문자열로 시작하고, 뒤에 whitespace, 그 뒤에 단어가 와야한다는 의미이다.
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 문자열을 사용한 첫 번째 줄만 매치된 것이다.
^를 첫째줄이 아닌, 각 라인의 처음으로 인식학 싶은 경우, 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))
#['python one', 'python two', 'python three']
4. VERBOSE, X
전문가들이 만든 정규식은 암호와 같다.( 지금 이 정도만 봐도 암호해석하는 기분인데, 실제로 전문가가 만든 것을 보면 진짜 외계어일 것 같긴 하다..ㅎㅎ👀)
정규식을 주석 또는 줄 단위로 구분하여 보기 좋고 이해하기 좋도록 하는 옵션이 re.VERBOSE 또는 re.X 옵션이다.
charref = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
위의 코드는 마치 외계어 같이 생겼다..
이를 주석을 적고, 여러 줄로 표현할 수 있도록 하는 것이 re.VERBOSE 옵션이다.
문자열에 사용된 whitespace는 컴파일할 때 제거되고([] 안에 사용한 공백 제외), 줄 단위로 #을 이용하여 주석문을 달 수 있다.
charref = re.compile(r"""
&[#] # Start of a numeric entity reference
(
0[0-7]+ # Octal form
| [0-9]+ # Decimal form
| x[0-9a-fA-F]+ # Hexadecimal form
)
; # Trailing semicolon
""", re.VERBOSE)
백슬래시 문제
\를 이용한 여러가지 패턴들이 존재한다. \section과 같은 문자열을 찾기 위한 정규식을 만든다면 \s와 구분할 필요가 있어보인다..!
\section
== [ \t\n\r\f\v]ection
따라서 \section을 매치하고 싶은 의도대로 매치하고 싶다면 \\section으로 작성해야 한다.
>>> p = re.compile('\\section')
만약 \\를 매치하고 싶다면 \\\\ 4 개나 매치해야 한다.
따라서, \가 반복되는 경우 컴파일 해야 하는 정규식이 raw string 임을 알려줄 수 있도록 r을 앞에 붙일 수 있다.
>>> p = re.compile(r'\\section')
정말 정규식은 이 책에서도 시작하기전에 어렵다고 하였는데,, 정말 양이 많은 것 같다..ㅎㅎㅎ
다음엔 강력한 정규표현식의 세계로!! 라는 마지막 챕터를 뿌셔보자 🔥
'TIL > 코테개념_python' 카테고리의 다른 글
[python] 입출력 및 주요라이브러리 문법 (0) | 2021.04.13 |
---|---|
[python] 강력한 정규 표현식 뿌시기 (0) | 2021.01.07 |
[python] 예외 처리 뿌시기 (0) | 2021.01.07 |
[python] 패키지 뿌시기 (0) | 2021.01.07 |
[python] 모듈 뿌시기 (0) | 2021.01.07 |