본문 바로가기
프로그래밍/정규표현식

[정규 표현식] 탐욕 수량자(Greedy Match)와 게으른 수량자(Lazy, Non-greedy Match)

by 부자 꽁냥이 2022. 10. 26.

이번 포스팅에서는 탐욕 수량자(Greedy Match)와 게으른 수량자(Lazy, Non-greedy Match)에 대한 개념을 소개하고 파이썬(Python)을 통한 예제를 알아보자. 이때 수량자에 대한 내용을 모르는 분들은 여기를 참고하면 좋다.


   탐욕 수량자(Greedy Match)와 게으른 수량자(Lazy, Non-greedy Match)

1) 탐욕 수량자(Greedy Match)

탐욕 수량자는 패턴 매칭이 중간에서 멈추지 않고 마지막까지 찾는 수량자를 말한다. 적당히를 모르고 욕심이 많아서 찾을 수 있는 곳까지 찾는다 하여 탐욕 수량자라고 하는 것 같다. 일반적으로 사용하는 수량자는 모두 탐욕 수량자이다.

 

예를 들어 'aacefasdfc'라는 문자열을  a.*c라는 패턴을 찾는다고 해보자. 온라인 정규 표현식 테스트 사이트인 regex101.com에 들어가서 테스트해보면 'aac'에서 멈춰도 되지만 맨 마지막에 'c'가 있어서 결국 전체 문자열인 'aacefasdfc'을 찾게 되는 것이다.

 

탐욕 수량자(Greedy Match)


2) 게으른 수량자(Lazy, Non-greedy Match)

게으른 수량자는 패턴 매칭 작업이 더 이루어질 수 있음에도 중간에 패턴을 발견하는 즉시 매칭 작업이 종료되는 수량자를 말한다. 일(패턴 매칭 작업)을 더 할 수 있음에도 중간에 끝마치기 때문에 게으른 수량자라고 불리는 것 같다. 게으른 수량자는 수량자 뒤에 물음표 '?'을 추가하면 된다.

 

예를 들어 'aacefsdfc'라는 문자열을  a.*?c라는 패턴을 찾는다고 해보자. 앞에서 살펴보았던 탐욕 수량자와는 달리 전체 문자열을 매칭할 수 있음에도 불구하고 중간에 'aac'를 매칭하고 작업을 종료하게 된다.

 

게으른 수량자(Lazy, Non-greedy Match)

 


3) 파이썬 예제

a. 기본

아래 코드는 탐욕 수량자와 게으른 수량자의 예시를 나타낸 것이다. 코드를 실행해보면서 차이점을 알 수 있다.

 

(1) .* vs .*?

string = 'accefcc'
print(re.match(r'a.*c', string).group())
# accefcc
print(re.match(r'a.*?c', string).group())
# ac

 

(2) .+ vs .+?

string = 'accefcc'
print(re.match(r'a.+c', string).group())
# accefcc
print(re.match(r'a.+?c', string).group())
# acc

 

(3) .? vs .??

string = 'accefcc'
print(re.match(r'a.?c', string).group()) ## a와 c 사이에 최대 문자 하나까지 찾으므로 acc가 매칭
# acc
print(re.match(r'a.??c', string).group()) ## a와 c 사이에 문자가 없어도 되므로 ac가 매칭
# ac

 

(4) {n, } vs {n, }?

string = 'accddee'
print(re.match(r'a.{2,}e', string).group())
# accddee
print(re.match(r'a.{2,}?e', string).group())
# accdde

 

(5) .+ vs .+?

string = 'accddeessee'
print(re.match(r'a.{2,8}e', string).group()) ## a와 e 사이에 최대 8개까지 문자가 있는지 확인
# accddeesse
print(re.match(r'a.{2,8}?e', string).group()) ## a와 e 사이에 2~8개수 범위 내에 문자열 발견 즉시 종료
# accdde

b. 응용

이번엔 좀 더 실용적인 예제를 알아보자. html에서 특정 태그를 찾고 싶을 때, 예를 들어 문자열 '<h2>Hello<h2>'에서 <h2>를 매칭하고 싶을 때 게으른 수량자를 활용할 수 있다. 이때 탐욕 수량자를 사용하면 어떻게 되는지도 함께 확인해보자.

 

string = '<h2>Hello<h2>'
print(re.match(r'<.+>', string).group())
# <h2>Hello<h2>
print(re.match(r'<.+?>', string).group())
# <h2>

 


댓글


맨 위로