[파이썬] 점프 투 파이썬 - 정규 표현식

2023. 6. 20. 11:27공부한 내용/점프 투 파이썬

1. 정규 표현식 살펴보기

1) 정규 표현식이란?

*정규 표현식(Regular Expressions)

-복잡한 문자열을 처리할 때 사용하는 기법

-파이썬만의 고유 문법이 아니라 문자열을 처리하는 모든 곳에서 사용

 

2) 메타 문자

*메타 문자(meta characters): 원래 그 문자가 가진 뜻이 아닌 특별한 용도로 사용하는 문자

*정규 표현식에서 사용하는 메타 문자: . ^ $ * + ? {} [] \ | ()

 

3) 문자 클래스 [ ]

*문자 클래스

-메타 문자: [ ]

-의미: [ ] 사이의 문자들과 매치

-[ ] 사이에는 어떤 문자도 들어갈 수 있음

 

(ex) [abc]: a, b, c 중 한 개의 문자와 매치

-a, b, c 중 하나라도 포함되어 있으면 매치

 

*[ ] 안의 두 문자 사이에 -를 사용하면 두 문자 사이의 범위를 의미

(ex) [a-zA-Z]: 알파벳 모두, [0-9]: 숫자

-단 문자 클래스 안에 ^ 메타 문자를 사용할 경우에는 반대(not)라는 의미를 가짐

(ex) [^0-9]: 숫자가 아닌 문자만 매치됨

 

4) Dot(.)

*줄바꿈 문자인 \n을 제외한 모든 문자와 매치됨을 의미하는 메타 문자

(ex) a.b: a와 b 라는 문자 사이에 줄바꿈 문자를 제외한 어떤 문자가 들어와도 모두 매치된다는 의미

 

※혼동하기 쉬운 예

*문자 클래스 [ ] 안에 Dot(.) 문자가 있는 경우

(ex) a[.]b: 이 때는 "모든 문자"라는 의미가 아닌 문자 "." 그대로를 의미

 

5) 반복(*)

*반복을 의미하는 * 메타 문자

*0번부터 무한대로 반복될 때 사용 (실제로는 메모리 제한으로 무한대가 아닌 2억 개 정도만 가능)

-* 바로 앞에 있는 문자가 0부터 무한대로 반복될 수 있음

(ex) ca*t: * 바로 앞에 있는 문자 a가 0부터 무한대로 반복될 수 있다는 의미

 

6) 반복(+)

*반복을 의미하는 + 메타 문자

*최소 1번 이상 반복될 때 사용

*0번부터 무한대로 반복될 때 사용하는 *와 차이를 보임

(ex) ca+t: + 바로 앞에 있는 문자 a가 1부터 무한대로 반복될 수 있다는 의미

 

7) 반복({m,n}, ?)

*{ } 메타 문자

-반복 횟수를 고정하는 의미

-{m, n} 정규식 사용 시 반복 횟수가 m부터 n까지 매치할 수 있음

-m 또는 n은 생략 가능 (생략된 m은 0과 동일, 생략된 n은 무한대(2억 개 미만)를 의미)

(ex) ca{2}t: { } 메타 문자 앞의 a가 반드시 2번 반복되어야만 매치

(ex2) ca{2, 5}t: { } 매타 문자 앞의 a가 2번~5번 반복되면 매치

 

*?

-{0,1}을 의미하는 메타 문자

(ex) ab?c: { } 메타 문자 앞의 b가 있어도 되고 없어도 된다는 의미

 

 

2. 정규 표현식 시작하기

1) re 모듈

*re(regular expression의 약어) 모듈

-파이썬이 정규 표현식을 지원하기 위해 제공하는 모듈

-파이선을 설치할 때 자동으로 설치되는 기본 라이브러리

 

*사용 방법

-re.compile

: 정규 표현식을 컴파일 -> 컴파일된 패턴(: 정규식을 컴파일한 결과) 객체 반환 -> 객체  p를 사용해 검색 수행

import re
p = re.compile("ab*") #ab가 0번 이상 나오는지 검사하고 싶은 경우

 

2) 문자열 검색 함수

import re
p = re.compile("[a-z]+")  #a-z가 한번 이상 나오는지 검사하고 싶은 경우

(1) match(): 문자열의 처음부터 정규식과 매치되는지 조사

*문자열이 정규식에 부합하면 match 개체 반환

*문자열이 정규식에 부합하지 않으면 None 반환

#문자열이 정규식에 부합할 경우
m = p.match("python")
print(m)
#> <re.Match object; span=(0, 6), match="python">  #match 객체를 돌려줌

#문자열이 정규식에 부합하지 않는 경우
m = p.match("3 python")
print(m)
#> None

 

(2) search: 문자열 전체를 검색해 정규식과 매치되는지 조사

*정규식에 부합하는 부분을 match 객체로 반환

m = p.search("3 python")
print(m)
#> <re.Match object; span=(2, 8), match="3 python">

 

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

result = p.findall("life is too short")
print(result)
#> ["life", "is", "too", "short"]

 

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

-반복 가능한 객체가 포함되는 각각의 요소는 match 객체

result = p.finditer("life is too short")
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">

 

3) match 객체의 메서드

*match와 search 메서드를 수행한 결과로 반환되는 match 객체의 메서드 통해 아래 확인 가능

-매치된 문자열

-매치된 문자열의 시작 위치

-매치된 문자열의 끝 위치

메서드 목적
group() 매치된 문자열을 돌려줌
start() 매치된 문자열의 시작 위치를 돌려줌
end() 매치된 문자열의 끝 위치를 돌려줌
span() 매치된 문자열의 (시작, 끝)에 해당하는 튜플을 돌려줌
import re
p = re.compile("[a-z]+")
m = p.match("python")

m.group()
#> "python"

m.start()
#> 0  #결과로 반환되는 match 객체의 start() 결과값은 항상 0: match 메서드는 항상 문자열의 시작부터 조사하기 때문

m.end()
#> 6

m.span()
#> (0, 6)
import re
p = re.compile("[a-z]+")
m = p.search("python")

m.group()
#> "python"

m.start()
#> 2

m.end()
#> 8

m.span()
#> (2, 8)

 

4) 컴파일 옵션

*정규식을 컴파일 할 때 옵션 사용 가능

옵션 이름 약어 설명
DOTALL S dot 문자(.)가 줄바꿈 문자를 포함해 모든 문자와 매치
IGNORECASE I 대/소문자에 관계 없이 매치
MULTILINE M 여러 줄과 매치
(^, $ 메타 문자의 사용과 관계 있는 옵션)
VERBOSE X verbose 모드 사용
(정규식을 보기 편하게 만들 수도 있고 주석 등 사용 가능)

 

(1) DOTALL, S

*dot(.) 메타 문자는 줄바꿈 문자(\n)를 제외한 모든 문자와 매치되는 규칙이 있는데, 만약 \n 문자도 포함하여 매치하고 싶다면 re.DOTALL 혹은 re.S 사용

 

(2) IGNORECASE, I

*re.IGNORECASE 혹은 re.I 사용

(ex) [a-z] 정규식은 소문자만을 의미하지만 re.I 옵션으로 대/소문자 구별 없이 매치됨

 

(3) MULTILINE, M

*정규식을 여러 줄과 매치

*re.MULTILINE / re.M 사용

 

(ex) ^와 $ 사용

-^: 문자열의 처음

-$: 문자열의 마지막

-메타 문자를 문자열의 처음/마지막이 아닌 각 라인의 처음/마지막으로 적용하고 싶은 경우 re.MULTILINE, re.M 사용

import re
p = re.compile("^python\s\w+", re.MULTILINE)

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

print(p.findall(data))
#> ["python one", "python two", "python three"]

 

(4) VERBOSE, X

*정규식을 주석 또는 줄 단위로 구분

-re.VERBOSE 혹은 re.X 사용

 

 

3. 정규 표현식 심화

1) 메타 문자

*+, *, [], {} 등의 메타 문자는 매치가 진행될 때 현재 매치되고 있는 문자열의 위치가 변경됨

*이와 달리 문자열을 소비시키지 않는 메타 문자도 존재

*문자열 소비가 없는(zero-width assertions) 메타 문자

 

2) | 메타 문자

*or과 동일한 의미

*A | B: A 또는 B라는 의미

p = re.compile("Crow|Servo")
m = p.match("CrowHello")
print(m)
#> <re.Match object; span=(0, 4), match="Crow">

 

3) ^메타 문자

*문자열의 맨 처음과 일치함을 의미

print(re.search("^Life", "Life is too short"))
#> <re.Match object; span-(0, 4), match="Life">

print(re.search("^Life", "My Life"))
#> None

 

4) $ 메타 문자

*^ 메타 문자와 반대의 경우

*문자열의 끝과 매치함을 의미

print(re.sesarch("short$", "Life is too short"))
#> <re.Match object; span=(12, 17), match="short">

print(re.sesarch("short$", "Life is too short, you need python"))
#> None

 

5) \A 메타 문자

*문자열의 처음곽 매치됨을 의미

*^ 메타 문자와 동일한 의미지만 re.MULTILINE 옵션 사용 시 다르게 해석됨

-^: 각 줄의 문자열의 처음과 매치

-\A: 줄과 상관없이 전체 문자열의 처음하고만 매치

 

6) \Z 메타 문자

*문자열의 끝과 매치됨을 의미

*\A와 동일하게 re.MULTILINE 옵션을 사용할 경우 $ 메타 문자와 다르게 해석됨

-$: 각 줄의 문자열의 끝과 매치

-\Z: 줄과 상관없이 전체 문자열의 끝하고만 매치

 

7) \b 메타 문자

*단어 구분자(Word boundary), 보통 단어는 whitespace에 의해 구분됨

p = re.compile("r\bclass\b")  #\bclass\b: 앞뒤가 whitespace로 구분된 class라는 단어와 매치
print(p.search("no class at all"))
#> <re.Match object; span=(3, 8), match="class">

-파이썬 규칙에 의하면 \b는 백스페이스(BackSpace)를 의미하므로, 정규식에서 사용할 때는 백스페이스가 아닌 단어 구분자임을 알리기 위해 raw string임을 알려주는 기호 r을 반드시 붙여야 함

 

8) \B 메타 문자

*\b 메타 문자와 반대의 경우

*whitespace로 구분된 단어가 아닌 경우에만 매치

p = re.compile(r"\Bclass\B")
print(p.search("no class at all"))
#> None

print(p.search("the declassified algorithm"))
#> <re.Match object; span=(6, 11), match="class">

print(p.search("one subclass is"))
#> None