복잡한 문자열을 처리할 때 사용하는 기법, 모든 언어 공통으로 사용됨
💡 example
import re
data = """
park 800905-1049118
kim 790102-1039485
"""
pat = re.compile("(\d{6})[-]\d{7}")
print(pat.sub("\g<1>-*******", data))
>>> park 800905-*******
kim 790102-*******
이런 문자열에 관련된 복잡한 문제를 해결 해야될 때 정규 표현식을 사용하면 짧고 간결하게 문제를 해결할 수 있음!
어떤 문자열의 규칙을 찾아서 어떤 거와 일치하는 것을 뭐로 바꿔라~ 이런 문제를 처리할 때 사용함!
그래서 이 문자가 어떤 규칙에 매치가 되는지 검사하는 여러가지 수식들이 있다.
[abc]
a.b
ca*t
ca+t
ca{2}t
ca{2,5}t
ab?c
import re
p = re.compile('ab*')
p(패턴객체)를 이용해서 우리가 원하는 문자열과 비교 해볼 수 있음!
이용하는 방법은 4가지가 있다
# 매치가 될 경우
import re
p = re.compile('[a-z]+') #a부터 z까지의 어떤 문자열이 1번 이상 반복되는 표현
m = p.match('python')
print(m)
>>> <re.Match object; span=(0, 6), match='python'>
# 매치가 안될 경우
import re
p = re.compile('[a-z]+') #a부터 z까지의 어떤 문자열이 1번 이상 반복되는 표현
m = p.match('3python')
print(m)
>>> None
import re
p = re.compile('[a-z]+') #a부터 z까지의 어떤 문자열이 1번 이상 반복되는 표현
m = p.search('3 python')
print(m)
>>> <re.Match object; span=(2, 8), match='python'>
import re
p = re.compile('[a-z]+') #a부터 z까지의 어떤 문자열이 1번 이상 반복되는 표현
m = p.findall('Life is too short')
print(m)
>>> ['ife', 'is', 'too', 'short']
import re
p = re.compile('[a-z]+') #a부터 z까지의 어떤 문자열이 1번 이상 반복되는 표현
m = p.finditer('Life is too short')
for r in m:
print(r)
>>> <re.Match object; span=(1, 4), match='ife'>
<re.Match object; span=(5, 7), match='is'>
<re.Match object; span=(8, 11), match='too'>
<re.Match object; span=(12, 17), match='short'>
method | 목적 |
---|---|
group() | 매치된 문자열을 리턴한다. |
start() | 매치된 문자열의 시작 위치를 리턴한다. |
end() | 매치된 문자열의 끝 위치를 리턴한다. |
span() | 매치된 문자열의 (시작, 끝)에 해당되는 튜플을 리턴한다. |
import re
p = re.compile('[a-z]+')
m = p.match('python')
print(m.group()) #python
print(m.start()) #0
print(m.end()) #6 -> 끝 인덱스는 5, 그 다음 수 출력
print(m.span()) #(0,6)
줄바꿈 문자도 포함하도록 만드는 옵션
import re
p = re.compile('a.b')
m = p.match('a\nb')
print(m) #None
# DOTALL, S
import re
p = re.compile('a.b', re.DOTALL)
m = p.match('a\nb')
print(m)
>>> <re.Match object; span=(0, 3), match='a\nb'>
대소문자를 무시하고 매칭할 수 있도록 해주는 옵션
import re
p = re.compile('[a-z]')
print(p.match('python')) #<re.Match object; span=(0, 1), match='p'>
print(p.match('Python')) #None
print(p.match('PYTHON')) #None
# IGNORECASE, I
import re
p = re.compile('[a-z]', re.IGNORECASE)
print(p.match('python'))
print(p.match('Python'))
print(p.match('PYTHON'))
>>> <re.Match object; span=(0, 1), match='p'>
<re.Match object; span=(0, 1), match='P'>
<re.Match object; span=(0, 1), match='P'>
꺽쇠(^)를 맨 처음만이 아닌 각 라인의 처음으로 인식시키는 옵션
^
: 맨 처음
\s
: 공백을 나타내는 문자
\w
: 알파벳, 숫자, _ 중 한 문자
# 멀티라인 옵션 안줬을 때
import re
p = re.compile('^python\s\w+') #맨 처음에 python이라는 글자가 나오고 그 다음 공백, 그리고 word(w)가 여러번 반복되는 것
data = """python one
life if too short
python two
python three"""
print(p.findall(data))
>>> ['python one'] #맨 처음 문장만 리턴
# 멀티라인 옵션을 준 경우
import re
p = re.compile('^python\s\w+', re.MULTILINE) #맨 처음에 python이라는 글자가 나오고 그 다음 공백, 그리고 word(w)가 여러번 반복되는 것
data = """python one
life if too short
python two
python three"""
print(p.findall(data))
>>> ['python one', 'python two', 'python three']
긴 정규표현식이 있을 때 나눠서 쓸 수 있게 만들어주는 옵션
정규표현식을 줄바꿈 할 경우 원래는 컴파일이 안되지만, verbose를 사용하면 공백들을 제거해줌!
import re
charref = re.compile(r'&[#](0[0-7]+|[0-9]+|x[0-9a-fA-F]+);')
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)
r(로우스트링)
이용하여 \ 그대로 사용!
💡 example
\section
p = re.compile('\\section')
p = re.compile('\\\\section')
p = re.compile(r'\\section')
\s
: 공백을 나타내는 문자이므로 (공백)ection으로 표시됨
따라서 \section을 입력해준다. but \ -> \ 로 표현되는 문제 발생.
따라서 \\section을 입력해줘야 원하는 \section 으로 표시됨!
이런 번거로움이 있을 때 사용하는 r
백슬래시가 있는 어떤 표현식이 있을 때 r(로우스트링)을 붙여서 백슬래시 두개만 붙여서 이게 공백이 아니다!만 표현해주면 정상적으로 동작할 수 있음
or
의 의미!import re
p = re.compile('Crow|Servo') #Crow 또는 Servo와 일치하는가
m = p.match('CrowHello')
print(m)
>>> <re.Match object; span=(0, 4), match='Crow'>
import re
print(re.search('Life', 'Life is too short'))
print(re.search('^Life', 'My Life'))
>>> <re.Match object; span=(0, 4), match='Life'>
None
import re
print(re.search('short$', 'Life is too short'))
print(re.search('short$', 'Life is too short, you need python'))
>>> <re.Match object; span=(12, 17), match='short'>
None
import re
p = re.compile(r'\bclass\b')
print(p.search('no class at all'))
print(p.search('the declassified algorithm'))
print(p.search('one subclass is'))
>>> <re.Match object; span=(3, 8), match='class'>
None
None
괄호를 이용해서 어떤 표현식을 묶어주는 것
import re
p = re.compile('ABC+') #C만 반복
m = p.search('ABCABCABC OK?')
print(m)
print(m.group())
>>> <re.Match object; span=(0, 3), match='ABC'>
ABC
# 그루핑 할 경우
import re
p = re.compile('(ABC)+')
m = p.search('ABCABCABC OK?')
print(m)
print(m.group())
>>> <re.Match object; span=(0, 9), match='ABCABCABC'>
ABCABCABC
추가로 그룹핑된 문자열에 이름을 따로 붙일수도 있음!
import re
p = re.compile(r"(?P<name>\w+)\s+((\d+)[-]\d+[-]\d+)")
m = p.search("park 010-1234-1234")
print(m.group("name"))
>>> park
import re
p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
print(p.search('Paris in the the spring').group())
>>> the the
import re
p = re.compile('.+:')
m = p.search("http://google.com")
print(m.group())
>>> http:
위 식에서 ' : ' 을 검색 조건에는 넣되, 결과에서는 빼고 싶은 경우
import re
p = re.compile('.+(?=:)') # ?=원하는 문자열
m = p.search("http://google.com")
print(m.group())
>>> http
import re
p = re.compile(".*[.](?!bat$).*$", re.M) # bat가 끝에 포함되지 않는 것 출력
l = p.findall("""
autoexec.exe
autoexec.bat
autoexec.jpg
""")
print(l)
>>> ['autoexec.exe', 'autoexec.jpg']
import re
p = re.compile(".*[.](?!bat$|exe$).*$", re.M) # bat 또는 exe가 끝에 포함되지 않는 것 출력
l = p.findall("""
autoexec.exe
autoexec.bat
autoexec.jpg
""")
print(l)
>>> ['autoexec.jpg']
sub('바꿀 문자열', '해당 문장'), 해당 문장에 정규표현식 조건에 부합한 문자열이 있으면 바꿀 문자열로 변경!
import re
p = re.compile('(blue|white|red)')
a = p.sub('colour', 'blue socks and red shoes') #정규표현식에 일치하는 것을 colour로 바꿔줌
print(a)
>>> colour socks and colour shoes
Greedy: 탐욕스러운
import re
s = '<html><head><title>Title</title>'
print(re.match('<.*>', s).group()) #Greedy
>>> <html><head><title>Title</title> #모든걸 가져오는 탐욕스러운 결과를 나타냄
Non-Greedy
반복되는 메타문자 뒤쪽에 물음표를 써주는 방식
import re
s = '<html><head><title>Title</title>'
print(re.match('<.*?>', s).group()) #Non-Greedy, 물음표는 최소한으로 반복하겠다는 의미!
>>> <html> #<.*?> -> 최소한으로 반복된 다음에 닫히므로 <html> 하나만 출력됨
Reference
참고한 영상