지난번에 프로그래머스 코딩테스트 문자를 풀면서
정규표현식에 대하여 처음 접하게 되었습니다.
오늘은 정규표현식에 대하여 한번 정리해보도록 하겠습니다.
해당 내용은 모두 '코딩 도장'의 내용을 정리한 내용입니다.
정규표현식(regular expression): 일정한 규칙을 가진 문자열을 표현하는 방법
1. 문자열 판단하기
re.match('패턴', '문자열'): 문자열에 해당 패턴하는 처음부터 매칭되는지 확인
import re
print(re.match('Hello','Hello world'))
print(re.match('goguma','Hello world'))
# Hello로 시작하지 않는 경우 None을 반환
print(re.match('Hello','HHHHHHello world'))
# 해당 문자열에 해당 문자가 있는지 판단하려면 find를 사용
print('HHHHHHello world'.find('Hello'))
>>><re.Match object; span=(0, 5), match='Hello'>
>>>None
>>>None
>>>5
re.search('패턴', '문자열') : 문자열 안에 해당 문자(패턴)이 있는지 확인
import re
# ^ : 해당 문자로 시작하는지
print(re.search('^Hello','Hello world'))
>>><re.Match object; span=(0, 5), match='Hello'>
# $ : 해당 문자로 끝나는지
print(re.search('world$','Hello world'))
>>><re.Match object; span=(6, 11), match='world'>
# | : or
print(re.search('Hello|world','goguma world'))
>>><re.Match object; span=(0, 5), match='world'>
지금까지 설명한 내용들도 물론 중요하지만 아래에서 설명할 내용들은 실전에서 많이 사용되기 때문에 반드시 익혀야하는 것들입니다.
2. 범위 판단하기
* : 0개 이상인지 판단
+ : 1개 이상인지 판단
import re
# 0-9가 0개 이상인지 판단
print(re.match('[0-9]*','123'))
>>><re.Match object; span=(0, 3), match='123'>
print(re.match('[0-9]*','abc'))
>>><re.Match object; span=(0, 0), match=''>
# a-z가 1개 이상인지 판단
print(re.match('[a-z]+','abc'))
>>><re.Match object; span=(0, 3), match='abc'>
# 여러 문자 숫자 조합도 가능
print(re.match('[a-zA-Z0-9]+', 'Hello1234'))
>>><re.Match object; span=(0, 9), match='Hello1234'>
print(re.match('[A-Z0-9]+', 'hello'))
>>>None
print(re.match('[$()a-zA-Z0-9]+', '$(document)'))
>>><re.Match object; span=(0, 11), match='$(document)'>
# 다음과 같이 활용 가능
# 문자열에서 a위치에 a가 0개 이상인지
print(re.match('a*b','b'))
>>><re.Match object; span=(0, 1), match='b'>
# 문자열에서 a위치에 a가 1개 이상인지
print(re.match('a+b','aab'))
>>><re.Match object; span=(0, 3), match='aab'>
?: 문자열에서 해당 위치에 0개 또는 1개인지 판단
. : .이 있는 위치에 문자(숫자)가 있는지 판단
import re
print(re.match('abc?','abcd'))
>>><re.Match object; span=(0, 3), match='abc'>
print(re.match('ab[0-9]?c','ab3c'))
>>><re.Match object; span=(0, 4), match='ab3c'>
# . 있는지 위치에 문자(숫자)가 있는지 확인
print(re.match('ab.c','abc'))
>>>None
print(re.match('ab.c','abxc'))
>>><re.Match object; span=(0, 4), match='abxc'>
문자{개수}, (문자열){개수} : 해당하는 문자(문자열)의 개수가 맞는지 판단
import re
print(re.match('h{3}','hhhhhello'))
>>><re.Match object; span=(0, 3), match='hhh'>
print(re.match('[0-9]{3}-[0-9]{4}-[0-9]{4}', '010-1000-1000'))
>>><re.Match object; span=(0, 13), match='010-1000-1000'>
[^범위] : 해당 범위를 제외한 나머지
^[범위] : 해당 범위로 시작하지는지 판단
print(re.search('[^A-Z]+', 'Hello'))
>>><re.Match object; span=(1, 5), match='ello'>
print(re.search('^[A-Z]+', 'Hello'))
>>><re.Match object; span=(0, 1), match='H'>
정규표현식에 사용되는 특수문자의 경우 \를 사용하여 표현
띄어쓰기는 ' '(공백) 혹은 \s 로 표현
# 특수문자 *, +, ?, ., ^, $, (, ) [, ], -
print(re.search('\*+', '1 ** 2'))
>>><re.Match object; span=(2, 4), match='**'>
# 띄어쓰기
print(re.match('[a-zA-Z0-9 ]+', 'Hello 1234'))
>>><re.Match object; span=(0, 10), match='Hello 1234'>
print(re.match('[a-zA-Z0-9\s]+', 'Hello 1234'))
>>><re.Match object; span=(0, 10), match='Hello 1234'>
\d: [0-9]와 같음. 모든 숫자
\D: [^0-9]와 같음. 숫자를 제외한 모든 문자
\w: [a-zA-Z0-9_]와 같음. 영문 대소문자, 숫자, 밑줄 문자
\W: [^a-zA-Z0-9_]와 같음. 영문 대소문자, 숫자, 밑줄 문자를 제외한 모든 문자
print(re.match('\d+', '1234'))
>>><re.Match object; span=(0, 4), match='1234'>
print(re.match('\D+', 'Hello'))
>>><re.Match object; span=(0, 5), match='Hello'>
print(re.match('\w+', 'Hello_1234'))
>>><re.Match object; span=(0, 10), match='Hello_1234'>
print(re.match('\W+', '(:)'))
>>><re.Match object; span=(0, 3), match='(:)'>
3. 그룹 사용하기
(정규표현식) (정규표현식) : 정규표현식을 괄호로 묶으면 그룹이 됩니다.
m = re.match('([0-9]+) ([0-9]+)', '10 295')
print(m.group(1))
>>>10
print(m.group(2))
>>>295
print(m.group())
>>>10 295
# 튜플 형식으로 반환
print(m.groups())
>>>('10', '295')
(?P<이름>정규표현식) : 그룹에 이름을 부여할 수 있음
# (문자,숫자,_그룹) + ( + (문자,숫자,_그룹) + )
m = re.match('(?P<func>[a-zA-Z0-9_]+)\((?P<arg>\w+)\)', 'print(1234)')
print(m.group('func'))
>>>print
print(m.group('arg'))
>>>1234
re.findall('패턴', '문자열') : 매칭되는 모든 문자열을 가져옴
print(re.findall('[0-9]+', '1 2 Fizz 4 Buzz Fizz 7 8'))
>>>['1', '2', '4', '7', '8']
패턴은 반드시 지켜야하지만 있어도 되고 없어도 되는 상황
print(re.match('[a-z]+(.[a-z]+)*$', 'hello.world')) # .world는 문자열이므로 패턴에 매칭됨
>>><_sre.SRE_Match object; span=(0, 11), match='hello.world'>
print(re.match('[a-z]+(.[a-z]+)*$', 'hello.1234')) # .1234는 숫자이므로 패턴에 매칭되지 않음
>>>None
re.match('[a-z]+(.[a-z]+)*$', 'hello') # .뒤에 문자열이 없어도 패턴에 매칭됨
>>><_sre.SRE_Match object; span=(0, 5), match='hello'>
4. 문자열 바꾸기
re.sub('패턴', '바꿀문자열' or 함수 , '문자열', 바꿀횟수) : 바꿀횟수가 지정되지 않는 경우 다 바꿈
※ m.group()을 사용한다는 것!!!!!!!!!
print(re.sub('apple|orange', 'fruit', 'apple box orange tree'))# apple 또는 orange를 fruit로 바꿈
>>>'fruit box fruit tree'
print(re.sub('[0-9]+', 'n', '1 2 Fizz 4 Buzz Fizz 7 8')) # 숫자만 찾아서 n으로 바꿈
>>>'n n Fizz n Buzz Fizz n n'
# 함수를 넣어 사용 가능
print(re.sub('[0-9]+', lambda m: str(int(m.group()) * 10), '1 2 Fizz 4 Buzz Fizz 7 8'))
>>>'10 20 Fizz 40 Buzz Fizz 70 80'
\\숫자, \\g<이름>, \\g<숫자> : 매칭된 문자열을 가져올 수 있음
print(re.sub('([a-z]+) ([0-9]+)', '\\2 \\1 \\2 \\1', 'hello 1234')) # 그룹 2, 1, 2, 1 순으로 바꿈
>>>'1234 hello 1234 hello'
print(re.sub('({\s*)"(?P<key>\w+)":\s*"(?P<value>\w+)"(\s*})', '<\\g<key>>\\g<value></\\g<key>>', '{ "name": "james" }'))
>>>'<name>james</name>'
print(re.sub('({\s*)"(\w+)":\s*"(\w+)"(\s*})', '<\\2>\\3</\\2>', '{ "name": "james" }'))
>>>'<name>james</name>'
5. 연습문제
import re
p = re.compile( )
emails = ['python@mail.example.com', 'python+kr@example.com', # 올바른 형식
'python-dojang@example.co.kr', 'python_10@example.info', # 올바른 형식
'python.dojang@e-xample.com', # 올바른 형식
'@example.com', 'python@example', 'python@example-com'] # 잘못된 형식
for email in emails:
print(p.match(email) != None, end=' ')
# 실행결과
True True True True True False False False
정답
이상으로 정규표현식에 대한 정리는 모두 마치도록 하겠습니다.
낯선 문법이다보니 여러번 읽어보면서 비슷한 문제를 봤을 때
적용해보려는 시도가 많이 필요할 꺼 같습니다.
해당 문제를 정규표현식으로 해결해보면 좋을 것 같습니다!
이상으로 정리를 마치도록 하겠습니다 ㅎㅎ
'파이썬' 카테고리의 다른 글
[PYTHON] Collections.Count() (0) | 2021.12.16 |
---|---|
[PYTHON] zip() (0) | 2021.12.14 |
[PYTHON] string 관련 함수 (0) | 2021.12.11 |
[PYTHON] set() (0) | 2021.12.08 |
[PYTHON] strip([char]) (0) | 2021.12.05 |