day 9 정규표현식 사용하기

4 minute read

정규표현식 사용하기

문자열 판단하기

import re
re.match('Hello', 'Hello, world!')     # 문자열이 있으므로 정규표현식 매치 객체가 반환됨


<re.Match object; span=(0, 5), match='Hello'>

문자열이 맨 앞에 오는지 맨 뒤에 오는지 판단하기

re.match('Python', 'Hello, world!')    # 문자열이 없으므로 아무것도 반환되지 않음
re.search('^Hello', 'Hello, world!')     # Hello로 시작하므로 패턴에 매칭됨

<re.Match object; span=(0, 5), match='Hello'>
re.search('world!$', 'Hello, world!')    # world!로 끝나므로 패턴에 매칭됨

<re.Match object; span=(7, 13), match='world!'>

지정된 문자열이 하나라도 포함되는지 판단하기

re.match('hello|world', 'hello')    # hello 또는 world가 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 5), match='hello'>

범위 판단하기

re.match('[0-9]*', '1234')    # 1234는 0부터 9까지 숫자가 0개 이상 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 4), match='1234'>
re.match('[0-9]+', '1234')    # 1234는 0부터 9까지 숫자가 1개 이상 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 4), match='1234'>
re.match('[0-9]+', 'abcd')    # abcd는 0부터 9까지 숫자가 1개 이상 없으므로 패턴에 매칭되지 않음

re.match('a*b', 'b')      # b에는 a가 0개 이상 있으므로 패턴에 매칭됨
<re.Match object; span=(0, 1), match='b'>
re.match('a+b', 'b')      # b에는 a가 1개 이상 없으므로 패턴에 매칭되지 않음

re.match('a*b', 'aab')    # aab에는 a가 0개 이상 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 3), match='aab'>
re.match('a+b', 'aab')    # aab에는 a가 1개 이상 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 3), match='aab'>

문자가 한 개만 있는지 판단하기

re.match('abc?d', 'abd')         # abd에서 c 위치에 c가 0개 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 3), match='abd'>
re.match('ab[0-9]?c', 'ab3c')    # [0-9] 위치에 숫자가 1개 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 4), match='ab3c'>
re.match('ab.d', 'abxd')         # .이 있는 위치에 문자가 1개 있으므로 패턴에 매칭됨

<re.Match object; span=(0, 4), match='abxd'>

문자 개수 판단하기

re.match('h{3}', 'hhhello')
<re.Match object; span=(0, 3), match='hhh'>
re.match('(hello){3}', 'hellohellohelloworld')
<re.Match object; span=(0, 15), match='hellohellohello'>
re.match('[0-9]{3}-[0-9]{4}-[0-9]{4}', '010-1000-1000')    # 숫자 3개-4개-4개 패턴에 매칭됨
<re.Match object; span=(0, 13), match='010-1000-1000'>
re.match('[0-9]{3}-[0-9]{4}-[0-9]{4}', '010-1000-100')   # 숫자 3개-4개-4개 패턴에 매칭되지 않음
re.match('[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}', '02-100-1000')    # 2~3개-3~4개-4개 패턴에 매칭됨
<re.Match object; span=(0, 11), match='02-100-1000'>
re.match('[0-9]{2,3}-[0-9]{3,4}-[0-9]{4}', '02-10-1000')  # 2~3개-3~4개-4개 패턴에 매칭되지 않음

숫자와 영문 문자를 조합해서 판단하기

re.match('[a-zA-Z0-9]+', 'Hello1234')    # a부터 z, A부터 Z, 0부터 9까지 1개 이상 있으므로
<re.Match object; span=(0, 9), match='Hello1234'>
re.match('[A-Z0-9]+', 'hello')    # 대문자, 숫자는 없고 소문자만 있으므로 패턴에 매칭되지 않음
re.match('[가-힣]+', '홍길동')    # 가부터 힣까지 1개 이상 있으므로 패턴에 매칭됨
<re.Match object; span=(0, 3), match='홍길동'>

특정 문자 범위에 포함되지 않는지 판단하기

re.match('[^A-Z]+', 'Hello')    # 대문자를 제외. 대문자가 있으므로 패턴에 매칭되지 않음
re.match('[^A-Z]+', 'hello')    # 대문자를 제외. 대문자가 없으므로 패턴에 매칭됨
<re.Match object; span=(0, 5), match='hello'>
 re.search('^[A-Z]+', 'Hello')        # 대문자로 시작하므로 패턴에 매칭됨
<re.Match object; span=(0, 1), match='H'>
re.search('[0-9]+$', 'Hello1234')    # 숫자로 끝나므로 패턴에 매칭됨
<re.Match object; span=(5, 9), match='1234'>

특수 문자 판단하기

re.search('\*+', '1 ** 2')                    # *이 들어있는지 판단
<re.Match object; span=(2, 4), match='**'>
re.match('[$()a-zA-Z0-9]+', '$(document)')    # $, (, )와 문자, 숫자가 들어있는지 판단
<re.Match object; span=(0, 11), match='$(document)'>
re.match('\d+', '1234')          # 모든 숫자이므로 패턴에 매칭됨
<re.Match object; span=(0, 4), match='1234'>
re.match('\D+', 'Hello')         # 숫자를 제외한 모든 문자이므로 패턴에 매칭됨
<re.Match object; span=(0, 5), match='Hello'>
re.match('\w+', 'Hello_1234')    # 영문 대소문자, 숫자, 밑줄 문자이므로 패턴에 매칭됨
<re.Match object; span=(0, 10), match='Hello_1234'>
re.match('\W+', '(:)')    # 영문 대소문자, 숫자, 밑줄문자를 제외한 모든 문자이므로 패턴에 매칭됨
<re.Match object; span=(0, 3), match='(:)'>

공백 처리하기

re.match('[a-zA-Z0-9 ]+', 'Hello 1234')     # ' '로 공백 표현
<re.Match object; span=(0, 10), match='Hello 1234'>
re.match('[a-zA-Z0-9\s]+', 'Hello 1234')    # \s로 공백 표현
<re.Match object; span=(0, 10), match='Hello 1234'>

참고 | 같은 정규표현식 패턴을 자주 사용할 때

 p = re.compile('[0-9]+')    # 정규표현식 패턴을 객체로 만듦
p.match('1234')             # 정규표현식 패턴 객체에서 match 메서드 사용
<re.Match object; span=(0, 4), match='1234'>
p.search('hello')           # 정규표현식 패턴 객체에서 search 메서드 사용

그룹 사용하기

m = re.match('([0-9]+) ([0-9]+)', '10 295')
m.group(1)    # 첫 번째 그룹(그룹 1)에 매칭된 문자열을 반환
'10'
m.group(2)    # 두 번째 그룹(그룹 2)에 매칭된 문자열을 반환
'295'
m.group()     # 매칭된 문자열을 한꺼번에 반환
'10 295'
m.group(0)    # 매칭된 문자열을 한꺼번에 반환
'10 295'
m = re.match('(?P<func>[a-zA-Z_][a-zA-Z0-9_]+)\((?P<arg>\w+)\)', 'print(1234)')
m.group('func')    # 그룹 이름으로 매칭된 문자열 출력

'print'
m.group('arg')     # 그룹 이름으로 매칭된 문자열 출력
'1234'

패턴에 매칭되는 모든 문자열 가져오기

re.findall('[0-9]+', '1 2 Fizz 4 Buzz Fizz 7 8')
['1', '2', '4', '7', '8']
re.match('[a-z]+(.[a-z]+)*$', 'hello.world')    # .world는 문자열이므로 패턴에 매칭됨
<re.Match object; span=(0, 11), match='hello.world'>
re.match('[a-z]+(.[a-z]+)*$', 'hello.1234')     # .1234는 숫자이므로 패턴에 매칭되지 않음
re.match('[a-z]+(.[a-z]+)*$', 'hello')          # .뒤에 문자열이 없어도 패턴에 매칭됨
<re.Match object; span=(0, 5), match='hello'>

문자열 바꾸기

re.sub('apple|orange', 'fruit', 'apple box orange tree')    # apple 또는 orange를 fruit로 바꿈
'fruit box fruit tree'
re.sub('[0-9]+', 'n', '1 2 Fizz 4 Buzz Fizz 7 8')    # 숫자만 찾아서 n으로 바꿈
'n n Fizz n Buzz Fizz n n'
def multiple10(m):        # 매개변수로 매치 객체를 받음
    n = int(m.group())    # 매칭된 문자열을 가져와서 정수로 변환
    return str(n * 10)    # 숫자에 10을 곱한 뒤 문자열로 변환해서 반환

re.sub('[0-9]+', multiple10, '1 2 Fizz 4 Buzz Fizz 7 8')
'10 20 Fizz 40 Buzz Fizz 70 80'
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'

찾은 문자열을 결과에 다시 사용하기

re.sub('([a-z]+) ([0-9]+)', '\\2 \\1 \\2 \\1', 'hello 1234')    # 그룹 2, 1, 2, 1 순으로 바꿈
'1234 hello 1234 hello'
re.sub('({\s*)"(\w+)":\s*"(\w+)"(\s*})', '<\\2>\\3</\\2>', '{ "name": "james" }')
'<name>james</name>'

image

re.sub('({\s*)"(?P<key>\w+)":\s*"(?P<value>\w+)"(\s*})', '<\\g<key>>\\g<value></\\g<key>>', '{ "name": "james" }')
'<name>james</name>'
re.sub('({\s*)"(\w+)":\s*"(\w+)"(\s*})', r'<\2>\3</\2>', '{ "name": "james" }')
'<name>james</name>'

연습문제: 이메일 주소 검사하기

import re
 
p = re.compile('^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')
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 

심사문제: URL 검사하기

import re
url = input()
result = None
if re.match('^(http://|https://)[a-zA-Z0-9-\.]+\.([a-zA-zZ0-9]+)(/)*[a-zA-Z0-9-=_,\./]*', url):
    result = True
else:
    result = False
 
print(result)


http://www.example.com/hello/world.do?key=python
True

Leave a comment