Regular Expression - Python re
정규식 표현 Regular Expression ( 통칭 RegEx)
Python에 내장된 re 모듈을 사용해서 정규식 표현을 해 보자.
정규식은 여러모로 사용할 일이 많습니다.
텍스트에서 패턴 찾을 때에 정규식 만한 것이 없기 때문인데요.
cli 환경에서 스크립트를 짜다보면 sed, grep과 함께 많이 사용하게 됩니다.
가장 활용하기 쉬운 python을 활용해서 설명하겠습니다.
우선 regex의 기본 사용법을 먼저 설명하고 후에 python의 re에서의 사용법을 작성하겠습니다.
Regex는 입력된 문자열에서 패턴을 찾는 기능입니다.
Python은 기본 내장으로 're'라는 라이브러리가 있습니다. regular expression의 약자 re를 사용합니다.
패턴은 \(escape)를 많이 사용하기 때문에 raw sting을 나타내는 r을 사용해서 python의 문자열을 입력해야합니다.
"String" 라고 쓰지 않고 r"String" 으로 작성합니다.
기본 문법
문자열
아무 문자열이나 입력하면 해당 문자열을 찾아 줍니다. 숫자열도 문자열과 동일하게 취급됩니다. 특수문자의 경우 escape \를 사용할 수 있습니다.
import re
txt = "Field. Friend fr!end"
#re.findall(expression, text) 는 text에서 expression에 해당하는 구문을 찾습니다.
print(re.findall(r"ie", txt)) # ['ie', 'ie']
print(re.findall(r"\!e",txt)) # ['!e']
txt2 = "123456 23456"
print(re.findall(r"234",txt2)) # ['234', '234']
print(re.findall(r"ie", txt)) # ['ie', 'ie']
문자 클래스들
\s, \d, \w, \x, \O, \D, 등을 사용하면 특정 문자 클래스에 속하는 문자들을 가져올 수 있습니다.
\s | 공백문자, 공백, 탭 등 공백을 나타내는 문자들 |
\d | 숫자, 0-9 |
\D | 숫자가 아닌 것 |
\w | 숫자, 문자 및 _ |
\W | 단어가 아닌 것 |
# 공백문자 찾기
txt1 = "white space"
txt2 = "white space"
print( re.findall(r"e\ss",txt1) ) # ['e s']
print( re.findall(r"e\ss",txt2) ) # ['e s']
print( re.findall(r"es",txt1) ) # []
# 숫자열
txt3 = "a2f akf a5f"
print( re.findall(r"a\df",txt3)) # ['a2f', 'a5f']
print( re.findall(r"a\Df",txt3))
txt4 = "1j 2j kj j"
# \w
print( re.findall(r"\wj", txt4)) # ['1j', '2j', 'kj']
txt5= "ff 12 f4 2f"
print( re.findall(r"\d\d", txt5)) #['12']
print( re.findall(r'\D\d', txt5)) #[' 1', 'f4', ' 2']
앵커
^과 $를 사용해서 앞과 시작에서 문자열을 찾을 수 있습니다.
^는 행의 시작, $는 행의 마지막을 지칭하는 문자입니다.
검색 문자열에 앞뒤에 붙이면 시작할 때 있는 문자열과, 마지막에 있는 문자열만 고를 수 있습니다.
txt7 = "this this this this"
print(re.findall(r"^this", txt7))
# sub는 문자열 치환(substitution)이다.
print(re.sub(r"^this" , "Begin", txt7)) # Begin this this this
print(re.sub(r"this$" , "End", txt7)) # this this this End
중괄호
중괄호를 통해서 반복의 수를 나타낼 수 있습니다.
복사할 문자{최소 반복 수, 최대 반복 수}
0은 0번이고, 아무것도 기입하지 않으면 무제한입니다.
txt8 = "Teth Teeth Teeeth Teeeeth"
print( re.findall("Te{1,3}th",txt8))# ['Teth', 'Teeth', 'Teeeth']
print( re.findall("Te{0,1}th",txt8))# ['Teth']
print( re.findall("Te{2,}th",txt8))# ['Teeth', 'Teeeth', 'Teeeeth']
수량자
*,+,? 를 통해서도 수량을 지정할 수 있습니다. 중괄호로도 똑같이 표현 할 수 있지만 간결합니다.
* : 0 또는 그 이상
+ : 1 또는 그 이상
? : 0 또는 1
txt8 = "Tth Teth Teeth Teeeth Tasdfabasdfth"
print( re.findall(r"Te*th",txt8)) # ['Tth', 'Teth', 'Teeth', 'Teeeth']
print( re.findall(r"Te+th",txt8)) # ['Teth', 'Teeth', 'Teeeth']
print( re.findall(r"Te?th",txt8)) # ['Tth', 'Teth']
print( re.findall(r"T[^e]*th",txt8)) # ['Tth', 'Tasdfabasdfth']
대괄호
해당하는 것 중 하나를 찾습니다. -를 사용하면 그 사이 값도 포함입니다.
[abc] : a,b,c 중 하나
[a-z] : a에서 z까지 중 하나
[0-9] : 0부터 9 사이에 하나. [0123456789]와 동일합니다.
[A-Za-z0-9] : 문자 숫자 아무거나.
^ 표시는 여집합 표시입니다. 해당 문자를 제외하고 가져옵니다.
txt9 = "egg Agg igg 3gg"
print(re.findall(r"[A-Za-z0-9]gg",txt9)) # ['egg', 'Agg', 'igg', '3gg']
print(re.findall(r"[aeiou]gg",txt9)) # ['egg', 'igg']
print(re.findall(r"[^aeiou]gg",txt9)) # ['Agg', '3gg']
| 또는
|(vertical bar)를 통해서 패턴 중 하나만 일치해도 찾을 수 있습니다.
txt10 = ' "asdf" <asdf> '
print( re.findall(r"<[^>]*>|\"[^\"]*\"",txt10))
# ['"asdf"', '<asdf>']
그룹 (), group
()을 통해서 그룹을 지정하고 반환을 각각 할 수 있습니다.
text = "My phone number is 123-456-7890"
match = re.search(r"(\d{3})-(\d{3})-(\d{4})", text)
if match:
print("Full match:", match.group(0)) # Entire match
print("Area code:", match.group(1)) # First group
print("Prefix:", match.group(2)) # Second group
print("Line number:", match.group(3)) # Third group
print("Groups :", match.groups())
여러 패턴을 찾고 한개씩 사용 가능합니다. group(0)와 groups는 전체를 반환합니다.
POSIX (python에서 사용 불가)
[:digit:] , [:alpha:], [:upper:],[:lower:]등 unix 시스템에서 사용가능한 키워드들이 있습니다. 아쉽지만 파이썬에서는 사용할 수 없으므로 이런 것이 있구나 정도로 알고 가시면 됩니다. linux에서 script 짤 때에 유용하게 쓸 수 있습니다.
Python re
python의 re에 있는 함수들이 있습니다.
다른 프로그래밍언어나 스크립트 등에서는 정규표현식의 문법은 비슷하나 사용법은 조금씩 다릅니다.
1. re.search()
search는 가장 처음 발견한 매칭을 찾아서 match object로 반환합니다. 만약 없으면 none을 반환합니다.
re.search(pattern, string, flags=0)
찾은 경우에만 match값이 참으로 취급되기 때문에 if문과 함께 사용할 수 있습니다.
text = "The quick brown fox jumps over 12 lazy dogs."
match = re.search(r"\d+", text) # Find the first number
if match:
print("Found:", match.group())
2. re.compile()
패턴을 미리 컴파일해서 사용할 수 있습니다. 재사용성이 증가합니다.
pattern_object = re.compile(pattern,flags=0)
pattern = re.compile(r"\d+")
matches = pattern.findall("abc 123 def 456 ghi 789")
print(matches)
3. re.sub()
문자열 치환(substitution)
모든 찾은 문자열을 교체합니다.
re.sub(pattern, replacement, string, count=0, flags=0)
text = "The price is $100"
new_text = re.sub(r"\$\d+", "[REDACTED]", text)
print(new_text)