>>> # 기본
>>> import re
>>>
>>> str = '010-1111-2222'
>>> ptn = r'\d\d\d-\d\d\d\d-\d\d\d\d' # 정규표현식 지정
>>>
>>> if re.match(ptn, str) : # str이 정규표현식(ptn)과 맞는지 검사
>>> print('{} is phone number', str)
>>> else :
>>> print('{} is not phone number', str)
>>>
>>> # fullmatch
>>> str = 'abc'
>>> ptn = r'ab'
>>> re.match(ptn, str) # True
>>> re.fullmatch(ptn, str) # False : 문장 전체가 맞아야 True 반환
>>>
>>> # 첫문자열 부터 검사하며 한번 일치 한 뒤에는 어떤 문자가 와도 상관없음
>>> bool(re.match(r'\d', '3')) # True
>>> bool(re.match(r'\d', '3aaa')) # True
>>> bool(re.match(r'\d', 'aaa3')) # False
1. 컴파일 vs 실행
- 정규표현식은 2개의 프로세스로 나뉜다 > 컴파일, 실행
- 컴파일 : 패턴을 일괄적으로 상태기계로 불리는 열거형 데이터 구조로 만듬
- 실행 : 일치 유무를 판단. 프로그램이 상태기계를 순회하면서 일치를 찾는다.
- re.compile : 정규표현식을 컴파일한다.
- re.match에 r'문자열'을 인수로 넣으면 호출마다 컴파일+실행 이 되지만(상태기계를 매번 만들어야 한다), re.compile로 미리 표현식을 컴파일 해 놓으면 실행만 동작한다.
>>> import re
>>>
>>> reg1 = re.compile(r'ca*b$')
>>>
>>> def test_item(s) :
>>> if re.match(reg1, s) :
>>> print(s, 'is a match.')
>>> else :
>>> print(s, 'is not a match.')
>>>
>>> test_item('caab')
>>> test_item('caaxxb')
- 위 코드의 경우 컴파일 1번 실행 2번을 거치게 된다.
2. 플래그
>>> if re.match('m*ack', 'Mack the Knife', re.IGNORECASE | re.DEBUG) :
>>> print('Success.')
- '|'를 써서 플레그를 중첩 시킬 수 있다.
3. 문법
[ 메타문자 ]
[ 문자집합 ]
[abc] # abc 중 하나
[^abc] # abc 아닌것 중 하나
[A-Z] # A-Z 중 하나
[+-*/] # +-*/ 중 하나, 특수문자 그대로 인식
- '^'는 [바로 다음에 올경우, '-'은 문자사이에 위치하는 경우 외에는 일반 문자 취급
- 어디에서든 일반문자로 취급하려면 ₩사용
[ 패턴 수량자 ]
[ 실습예제 ]
암호에 다음 규칙을 검사하라.
1. 모든 문자는 대문자 혹은 소문자, 숫자 혹은 언더스코어(_), 혹은 구두접 문자(@, #, $, %, ^, &, *. !)다.
2. 최소 8자
3. 최소한 글자 1개 포함
4. 최소한 숫자 1개 포함
5. 최소한 구두점 문자 1개 포함
>>> import re
>>>
>>> pat1 = r'(\w|[@#$%^&*!]){8,}$' # 1, 2번 조건
>>> pat2 = r'.*\d' # 4번 조건
>>> pat3 = r'.*[a-zA-Z]' # 3번 조건
>>> pat4 = r'.*[@#$%^&*!]' # 5번 조건
>>>
>>> def verify_passwd(s) :
>>> b = (re.match(pat1, s) and re.match(pat2, s) and
>>> re.match(pat3, s) and re.match(pat4, s) )
>>> return bool(s)
4. Match 객체 사용
>>> import re
>>>
>>> pat = r'(a+)(b+)(c+)'
>>> m = re.match(pat, 'abbccceeee')
>>>
>>> for i in range(m.lastindex + 1) : # lastindex=3
>>> print(i, '. ', m.group(i), sep='')
>>>
0. abbccc
1. a
2. bb
3. ccc
5. search
- 패턴의 문자열에 대한 포함 여부 검색.
- match와 달리 검색 문자열의 첫문자부터 일치하지 않아도 된다.
>>> import re
>>> m = re.search(r'\d{2,}', '1 set of 23 owls, 999 doves.')
>>> print('"', m.group(), '" found at ', m.span(), sep='')
"23" found at (9, 11)
- 패턴에 맞는 문자열 "23"을 찾았고 위치는 9~11번 인덱스사이에 있다.
6. findall
- 대상_문자열 에서 패턴에 해당하는 모든 결과를 리스트로 반환
>>> import re
>>> s = 'What is 1,000.5 times 3 times 2,000?'
>>> print(re.findall(r'\d[0-9,.]*', s))
[ '1,000.5', '3', '2,000' ]
[ findall 그룹화 오류 ]
>>> pat = r'\d{1,3}(,\d{3})*(\.\d)?' # 숫자 미국 표준 포맷
>>> print(re.findall(pat, '12,000 monkeys and 55.5 cats.'))
[ (',000', ''), ('', '.5') ]
- 예상된 결과(12,000, 55.5)와 다르다
- pat의 ()가 그룹화로 인식 되었기 때문. 이는 다음과 같이 동작한다.
1. pat에 맞는 문자열 인식 '12,000'
2. 1번째 그룹패턴 인식 > ',000'
3. 2번째 그룹패턴 인식 > 없음
4. 1,2번 그룹을 튜플로 묶어 출력
- match객체에서의 0번째는 전체 패턴 결과를 출력하지만 여기선 그건 없는 것 같음.
>>> pat = r'(\d{1,3}(,\d{3})*(\.\d)?)' # 숫자 미국 표준 포맷
>>> st = re.findall(pat, '12,000 monkeys and 55.5 cats.')
>>> for item in st :
... print(item[0])
12,000
55.5
- 패턴 전체를 그룹화 하면 전체패턴이 1번째 그룹으로 인식되어 0번인덱스에 원하는 결과가 출력된다.
7. 반복패턴
>>> import re
>>>
>>> str = 'The cow jumped over the the moon Moon.'
>>> m = re.search(r'(\w) \1', str) # \1 : (\w)로 찾은 것과 동일한 단어
>>> print(m.group(), '...found at', m.span())
the the ...found at (20, 27)
>>> # flag 사용
>>> m = re.search(r'(\w) \1', str, flags=re.I) # re.IGNORECASE : 대소문자 무시
moon Moon ...found at (28, 37)
- \숫자 : 그룹을 지칭. 해당 그룹에 매칭된 문자열과 동일한(패턴X, 내용O) 문자열을 검색
8. 교체하기
>>> import re
>>> s1 = 'Get me a new dog to befriend my dog.'
>>> s2 = re.sub('dog', 'cat', s1)
>>> print(s2)
Get me a new cat to befriend my cat.
>>>
>>> # 반복패턴
>>> s1 = 'The the cow jumped over over the moon.'
>>> s2 = re.sub('(\w+) \1', '\1', s1, flags=re.I)
>>> print(s2)
The cow jumped over the moon.
'Python > 공통이론' 카테고리의 다른 글
Python - 파일 / 디렉터리 시스템 (0) | 2023.05.23 |
---|---|
Python - 고급 정규표현식 (0) | 2023.05.05 |
Python - format 함수&메서드의 사양 필드 (0) | 2023.04.17 |
Python - repr (0) | 2023.04.17 |
Python - format 메서드 (0) | 2023.04.14 |