:: python

python :: 파이썬 re 로 정규식 패턴 문자열 처리하기 (search/match/split/sub/compile)

토람이 2021. 12. 29. 11:12

re문자열 내 특정 패턴을 검색, 치환, 제거할 수 있는

파이썬 정규 표현식(Regular Expression) 라이브러리이다.

 

re 가 패턴을 인식하는 방법은 다음과 같다.

1) 정규식 작성

   : 특정 문자를 인식하기 위한 패턴을 정규식으로 작성한다. (내가 할 일)

2) re 에 정규식 적용

   : 작성한 패턴을 re 에 적용시키면 re 는 이를 가지고 정규식 객체를 생성한다.

3) 패턴 감지

   : 생성된 정규식 객체는 자동으로 문자열 내 해당 패턴을 감지할 수 있다.

 

 

즉, 내가 작성한 정규식을 토대로 문자열 내 패턴을 감지하는 것이다.

 

코딩하다보면 한 번 쯤은 꼭 정규식을 접하게 되는데

뭔가 더럽게(?) 생긴데다 규칙이 잘 외워지지도 않는다.

(그런데도 패턴 인식에 있어서 정말 많이 사용되는 표현식이다.)

 

 

내가 자주 사용하는 정규식 규칙들을 정리해 봄!

 

<선택>

표현식(규칙) 적용 예시 적용 예시 해석
| or A|B A 또는 B
[] or (대괄호 안에 있는 문자열) [ABC] A 또는 B 또는 C


<반복>

표현식(규칙) 적용 예시 적용 예시 해석
* 바로 앞 문자열 0개 이상 반복 BA* B, BA, BAA, ...
+ 바로 앞 문자열 1개 이상 반복 BA+ BA, BAA, ...
? 바로 앞 문자열 0 or 1개 반복.
즉, 나오거나 안나오거나.
BA? B, BA
{n} 바로 앞 문자열 n개 반복 AB{2} ABB
{n,} 바로 앞 문자열 n개 이상 반복 AB{2,} ABB, ABBB, ...
{n,m} 바로 앞 문자열 n개 이상 m개 이하 반복 A(BC){2,4} ABCBC, ABCBCBC, ABCBCBCBC


<인식 타입>

표현식(규칙)
\s 공백(space) 한 개
\w 문자 or 숫자 한 개
\W 문자 or 숫자가 아닌 것
\d 숫자 한 개
\D 숫자가 아닌 문자 한 개
. 모든 문자 한 개
^ 문자열 시작
$ 문자열 끝

 

 

이제 이 정규식 표현들을 적용할 re 의 주요 함수들을 알아보자.

 

 

1. re.search (검색)

re.search(pattern, string)

문자열을 스캔하여 정규식 패턴이 일치하는 첫 번째 위치를 찾는다. (찾지 못하면 None 반환)

예를 들어 날짜를 인식하는 정규식 패턴을 search 에 적용하면,

pattern = "([0-9]+년)\s*([0-9]+월)\s*([0-9]+일)"
a = re.search(pattern, "2021년 12월 29일 입니다. 내일은 2021년 12월 30일 이에요.")


# print(a)
# <re.Match object; span=(0, 13), match='2021년 12월 29일'>

위와 같이 첫 번째 인식한 결과를 객체로 반환한다.

 

반환된 객체에서 유용한 정보를 뽑아내보자.

# 인식패턴 시작 index
a.start()  # 0

# 인식패턴 끝 index
a.end()  # 13

# 인식패턴 문자열 출력
a.group()  # '2021년 12월 29일'

# 그 외 부분적으로 인식된 패턴들 모음
a.groups()  # ('2021년', '12월', '29일')

 

.groups() 를 보면 알 수 있듯이, re 는 전체 패턴에 대한 인식 결과물 외에도

부분적인 패턴 일치 결과물들도 저장해두는 걸 알 수 있다.

부분 일치 결과물들도 활용이 가능하다는 점 참고!

 

a.group()  # '2021년 12월 29일'
a.group(0)  # '2021년 12월 29일'
a.group(1)  # '2021년'
a.group(2)  # '12월'
a.group(3)  # '29일'
a.group(4)  # IndexError: no such group

 

어쨌거나 우리가 원하는 전체 패턴 인식 결과물은 .group() 혹은 .group(0) 으로 얻을 수 있다.

 

 

2. re.match (검색)

re.match(pattern, string)

search 와 유사하게 검색의 기능을 하지만 문자열의 시작 부분에서만 일치를 검사한다.

(search 는 문자열의 아무 곳에서나 일치하면 인식 가능)

 

re.match("c", "abcdef")  # 아무 것도 반환하지 않음
re.match("c", "cdef")  # <re.Match object; span=(0, 1), match='c'>

# search 는?
re.search("c", "abcdef")  # <re.Match object; span=(2, 3), match='c'>

 

 

3. re.split (쪼개기)

re.split(pattern, string)

문자열을 패턴 기준으로 쪼갠다.

pattern = "[0-9]"

a = re.split(pattern, "오늘은 29일 이에요")

# a
# ['오늘은 ', '', '일 이에요']

숫자를 인식하는 패턴으로 split 을 적용하면 위와 같다.

2 와 9 를 기준으로 문장이 쪼개진 것을 알 수 있다. (리스트로 반환)

 

 

4. re.sub (치환)

re.sub(pattern, repl, string)

string 에서 pattern 을 찾아서 repl 로 치환한다.

pattern = "[0-9]"

b = re.sub(pattern, "a", "오늘은 29일 이에요")

# b
# '오늘은 aa일 이에요'

 

숫자를 찾아 'a' 로 치환한 것을 알 수 있다.

 

 

5. re.compile (컴파일)

정규식 패턴을 정규식 객체로 컴파일한다.

prog = re.compile(pattern)

 

정규식 객체 prog 를 가지고 위에서 설명한 search, match, split 등등을 할 수 있다.

 

prog = re.compile(pattern)
a = prog.search("2021년 12월 29일 입니다.")

# print(a)
# <re.Match object; span=(0, 13), match='2021년 12월 29일'>

 

이런 식으로, 컴파일한 객체에 위 함수들을 동일하게 적용하면 된다.

 

 

Q. re.search  vs  정규식객체에서 search 호출 차이점

 

그럼 위처럼 re.search 를 사용하는 것과 컴파일된 객체에서 search 를 호출하는 건 어떤 차이가 있을까?

 

# 1
prog = re.compile(pattern)
a = prog.search("2021년 12월 29일 입니다.")

# 2
a = re.search(pattern, "2021년 12월 29일 입니다.")

기능상으로 동일하다.

 

 

다만, 하나의 정규식 패턴이 여러 번 사용될 때 compile 을 사용하는 것이 효율적이다.

pattern = "([0-9]+년)\s*([0-9]+월)\s*([0-9]+일)"

# 1
prog = re.compile(pattern)
a = prog.search("2021년 12월 29일 입니다.")
b = prog.search("내일은 2021년 12월 30일 입니다.")

# 2
a = re.search(pattern, "2021년 12월 29일 입니다.")
b = re.search(pattern, "내일은 2021년 12월 30일 입니다.")

 

아래의 경우처럼 re.search 를 계속 하면

동일한 패턴에 대해 정규식 객체를 계속해서 생성하게 되지만,

 

위의 경우처럼 생성한 정규식 객체를 재활용하면 보다 효율적일 수 있다.

 

 

 

광고 cIick은 토람코에 큰 힘이 됩니다 ♥

300x250