#6 정규 표현식

JIY00N·2023년 2월 2일
0

Python

목록 보기
6/9
post-thumbnail

2023.02.02

0. 시작하기전

이번 포스트에서는 파이썬 정규 표현식에 관해 공부를 해보자
정규 표현식은 처음 접하면 이해하기 어렵지만 코드를 간편하고 직관적이게 작성할 수 있다.
차근차근 하나씩 파이썬 정규 표현식에 관해 공부해보자 !

1. 정규 표현식

정규 표현식은 복잡한 문자열을 처리할 때 사용하는 기법이다.

1-1 메타문자

  1. 문자 클래스 []
    ✔ [] 사이의 문자들과 매치
    ✔ [a-zA-Z] = 알파벳 모두, [0-9] = 숫자 (하이픈(-)의 의미 = 범위)
    ✔ 자주 사용하는 문자 클래스
    \d - 숫자와 매치, [0-9]와 동일
    \D - 숫자가 아닌것과 매치, [^0-9]
    \s - whitespace 문차와 매치(공백 표현 문자)
    \S - whitespace가 아닌것과 매치
    \w - 문자+숫자와 매치
    \W - 문자+숫자가 아닌것과 매치
정규식
[abc]

문자열   매치여부   설명
a       Yes       "a"는 정규식과 일치하는 문자 "a"가 있으므로 매치
before  Yes       "before"는 정규식과 일치하는 문자 "b"가 있으므로 매치
dude    No        "dude"는 정규식과 일치하는 문자가 없으므로 매치 x
  1. Dot(.)
    ✔ 줄바꿈 문자(\n)을 제외한 모든 문자와 매치
정규식
a.b # a와 b사이의 줄바꿈 문자를 제외한 어떤 문자가 들어가도 모두 매치

문자열  매치여부  설명
aab    Yes      "aab"는 가운데 문자 "a"가 모든 문자를 의미하는 .과 일치하므로 매치
a0b    Yes      "a0b"는 가운데 문자 "0"이 모든 문자를 의미하는 .과 일치하므로 매치
abc    No       "abc""a""b"사이에 하나 이상의 문자가 없으므로매치 x

a[.]b = "a+Dot(.)문자+b"
a와 b사이에 Dot(.)문자가 있으면 매치
  1. 반복(*)
    ✔ 반복횟수가 0부터 시작
정규식
ca*t # *문자 바로 앞에 있는 a가 0번 이상 반복되면 매치

문자열  매치여부  설명
ct     Yes      "a"0번 반복하므로 매치
cat    Yes      "a"1번 반복하므로 매치
caaat  Yes      "a"3번 반복하므로 매치
  1. 반복(+)
    ✔ 반복횟수가 1부터 시작
정규식
ca+t # +문자 바로 앞에 있는 a가 1번 이상 반복되면 매치

문자열  매치여부  설명
ct     No       "a"0번 반복하므로 매치x
cat    Yes      "a"1번 반복하므로 매치
caaat  Yes      "a"3번 반복하므로 매치
  1. 반복({m,n},?)
    ✔ 반복횟수의 제한 (m부터 n까지)
1. {m}
ca{2}t = a가 2번 반복되면 매치

2. {m,n}
ca{2,5}t = a가 2~5번 반복되면 매치

3. ? = {0,1}
ab?c = b가 0~1번 사용되면 매치

1-2 re 모듈

✔ 파이썬 정규 표현식 지원 모듈
✔ re.compile을 사용하여 정규 표현식을 컴파일 함

>>> import re
>>> p = re.compile('ab*')
# re.compile의 결과를 돌려주는 객체 p를 사용

1-3 정규식을 사용한 문자열 검색

  1. match() - 문자열의 처음부터 정규식과 매치되는지 조사
    ✔ match 객체의 메서드
    - group() - 매치된 문자열을 돌려줌
    - start() - 매치된 문자열의 시작 위치를 돌려줌
    - end() - 매치된 문자열의 끝 위치를 돌려줌
    - span() - 매치된 문자열의 (시작,끝)에 해당하는 튜플을 돌려줌

  2. search() - 문자열 전체를 검색하여 정규식과 매치되는지 조사

  3. findall() - 정규식과 매치되는 모든 문자열을 리스트로 돌려줌

  4. finditer() - 정규식과 매치되는 모든 문자열을 반복 가능한 객체로 돌려줌

>>> import re
>>> p = re.compile('[a-z]+')

# 1. match 사용
>>> m = p.match("python")
>>> print(m)
<re.Match object; span=(0,6), match='python'> # match 객체를 돌려줌

# match 일반적 프로그램
p = re.compile(정규표현식)
m = p.match("조사할 문자열")
if m:
	print('Match found: ', m.group())
else:
	print('No match')

# match 메서드 예
>>> m = p.match("python")
>>> m.group()
'python'
>>> m.start()
0
>>> m.end()
6
>>> m.span()
(0,6)

# 2. search 사용
>>> m = p.search("python")
>>> print(m)
<re.Match object; span=(0,6), match='python'>

# 3. findall 사용
>>> result = p.findall("Life is too short")
>>> print(result)
['Life', 'is', 'too', 'short']

# 4. finditer 사용
>>> result = p.finditer("life is too short")
>>> print(result)
<callable_iterator object at 0x0aF5E390>
>>> 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'>

1-4 컴파일 옵션

  1. DOTALL(S) - dot 문자(.)가 줄바꿈 문자를 포함하여 모든 문자와 매치
>>> import re
>>> p = re.compile('a.b')
>>> m = p.match('a\nb') # \n과 매치되지않음
>>> print(m)
None

>>> p = re.compile('a.b', re.DOTALL) #re.DOTALL=re.S
>>> m = p.match('a\nb')
>>> print(m)
<re.Match object; span=(0,3), match='a\nb'>
  1. IGNORECASE(I) - 대,소문자에 관계 없이 매치
>>> import re
>>> p = re.compile('[a-z]',re.I)
# 대 소문자 관계없이 매치
>>> m = p.match('python') 
<re.Match object; span=(0,1), match='p'>
>>> m = p.match('Python') 
<re.Match object; span=(0,1), match='P'>
>>> m = p.match('PYTHON') 
<re.Match object; span=(0,1), match='P'>
  1. MULTILINE(M) - 여러줄과 매치(^: 문자열의 처음, $:문자열의 마지막)
>>> import re
>>> p = re.compile("^python\s\w+",re.MULTILINE) 
# ^python\s\w+
# 위의 뜻은 python이라는 문자열로 시작하고 그 뒤에 spacewhite 그 뒤에 단어가 와야함

data = """python one
life is too short
python two
you need python
python three"""

print(p.findall(data))
['python one','python two','python three']
  1. VERBOSE(X) - 가독성을 높이고 주석 사용 가능
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)

1-5 백슬래시 문제

>>> p = re.compile(r'\\section')
# r문자를 사용하여 \\\\를 의미

2. 강력한 정규 표현식

2-1 메타문자

✔ 문자열 소비가 없는 메타문자
1. | - or과 동일한 의미
2. ^ - 문자열의 맨 처음과 매치함
3. & - 문자열의 끝과 매치함
4. \A - 문자열의 처음과 매치함
(MULTILNE과 쓸때는 줄과 상관없이 전체 문자열의 처음하고만 매치)
5. \Z - 문자열의 끝과 매치함
(MULTILNE과 쓸때는 줄과 상관없이 전체 문자열의 끝과 매치)
6. \b - 단어 구분자(보통 whitespace에 의해 구분)
7. \B - whitespace로 구분된 단어가 아닌 경우에만 매치

2-2 그루핑

✔ 그룹을 만들어주는 메타문자 ()
✔ 특정 부분의 문자열만 뽑아내는데 유용
✔ 그루핑한 문자열 재참조 가능

>>> p = re.compile(r"(\w+)\s+\d+[-]\d+[-]\d+")
>>> m = p.search("park 010-1234-1234")
>>> print(m.group(1))
park
# group(0) - 매치된 전체 문자열
# group(1) - 첫번째 그룹에 해당하는 문자열
# group(n) - n번째 그룹에 해당하는 문자열

# 재참조 메타문자 = \1(\1은 정규식의 그룹중 첫번째 그룹)
>>> p = re.compile(r'(\b\w+)\s+\1')
>>> p.search('Paris in the the spring').group()
'the the'

2-3 그루핑된 문자열에 이름 붙이기

✔ 그룹을 인덱스가 아닌 이름으로 참조
✔ 이름 붙이기 (?P<그룹이름>...)
✔ 정규식 안에서 재참조 가능 (?P=그룹이름)

>>> p = re.compile(r"(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)")
>>> m = p.search("park 010-1234-1234")
>>> print(m.group("name"))
park

# 재참조 (?P=그룹이름)
>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
>>> m = p.search('Paris in the the spring').group()
'the the'

2-4 전방 탐색

  1. 긍정형 전방 탐색(?=...) - ...에 해당하는 정규식과 매치되어야 하며 조건이 통과되어도 문자열이 소비되지 않는다.
# http:의 결과를 http로 바꾸기
>>> p = re.compile(".+(?=:)")
>>> m = p.search("http://google.com")
>>> print(m.group())
http
  1. 부정형 전방 탐색(?!...) - ...에 해당하는 정규식과 매치되지 않아야 하며 조건이 통과되어도 문자열이 소비되지 않는다.
# 확장자가 bat이 아닌경우에만 통과
.*[.](?!bat$).*$

2-5 문자열 바꾸기

✔ sub 메서드를 사용
✔ sub(바꿀문자열, 대상문자열, count=바꿀횟수)
✔ subn(변경된 문자열, 바꾼횟수) - sub와 동일하지만 튜플로 반환

>>> p = re.compile('(blue¦white¦red)')
>>> p.sub('colour','blue socks and red shoes')
'colour socks and colour shoes'

2-6 Greedy vs Non-Greedy

✔ non-greedy문자인 ?를 사용하면 *의 탐욕 제한 가능
✔ 가장 최소한의 반복을 수행하도록 도와줌

>>> s = '<html><head><title>Title</title>'
>>> len(s)
32
>>> print(re.match('<.*>',s).span())
(0,32)
>>> print(re.match('<.*>',s).group())
<html><head><title>Title</title>

>>> print(re.match('<.*?>',s).group())
<html>

3. The End

이번 포스트를 마지막으로 작성하면서 느낀 점은 무엇이든 간에 꾸준히 공부하지 않으면 금방 까먹거나 감을 잃어버린다는 것이다.
그런 불상사가 일어나지 않도록 일주일간 공부하면서 정리한 내용들을 잘 익히고 반복 학습하자 :)
Python 포스트 시리즈는 'Do it! 점프 투 파이썬'을 바탕으로 작성하였다.

이전 포스트 Python-5 https://velog.io/@jiyoon2/Python-5

profile
블로그 이전 했습니다. https://yoon-log.vercel.app/

0개의 댓글