이글루스 | 로그인  


정규표현식 룩어라운드(lookaround)

정규표현식을 공부하면서 기본적인 것이지만,

이해 및 인식이 잘 되지 않아 헤매고 있는 것이

룩어라운드(lookaround)입니다.

따라서 간단히 정리하겠습니다.

 

 

룩어라운드는 단어 경계를 나타내는 메타 문자인 [/b]나

앵커인 [^](문자열 앞), [$](문자열 끝)와 마찬가지로

텍스트에 매치되지 않고 텍스트 안에 있는 어떤 위치에 매치된다.

 

 

예제 1

문자열 : "see Jeffs book"

정규식 : s/\bJeff(?=s\b)/Jeff`/g

 

위 정규식은 'Jeffs'를 'Jeff`s'로 바꾸고자 할 때 쓰입니다.

그리 실용적이지는 못하지만,

룩어라운드의 일부분인 긍정형 룩어헤드(positive lookahead)의 훌륭한 예입니다.

 

살펴보면 다음과 같습니다.

'[단어경계]Jeff'를 맞춘 후 룩어헤드를 시도합니다.

룩어헤드는 그 위치(Jeff 다음 위치)에서 's[단어경계]'이 맞는 경우

전체적으로 정규식에 맞는 문자열이 됩니다.

하지만 여기서 실제 매치되는 부분은 Jeff뿐이고,

나머지(s\b)는 위치를 선택하는 부분입니다.

다시 말하자면 'Jeff'만 매치하는 척 하면서 실제로는 'Jeffs'를 모두 체크합니다.'

 

 

예제 2

문자열 : "by Jeffrey Friedl, Jeffley, Jeff, Jefferson"

정규식 : (?=Jeffrey)Jeff

 

위 정규식은 문자열의 Jeff에 일치합니다.

하지만 Jeffley, Jeff, Jefferson에는 일치하지 않습니다.

왜냐하면 앞의 룩어헤드가 있기 때문입니다.

 

살펴보면 다음과 같습니다.

'Jeffrey를 찾아 맞춘 후 실제 매치는 Jeff만 한다.'

따라서 다음과 같은 정규식을 실행시키면 다음과 같습니다.

c2

바뀐 부분을 보면 'Jeffrey'가 'NoSyurey'로 바뀌어져 있습니다.

(영어학원에서 쓰는 저의 닉네임이 Jeff라서 이렇게 하였습니다.)

위에서 얘기했듯이 다른 Jeff는 변하지 않았습니다.

그리고 'Jeffrey'를 찾았지만, 'NoSyu'라 바뀌는 것은 'Jeffrey'의 'Jeff'뿐입니다.

 

참고로 '(?=Jeffrey)Jeff'와 'Jeff(?=rey)'는 같습니다.

 

 

예제 3

문자열 : 1234567890

정규식 : s/(?<=\d)(?=(\d\d\d)+$)/,/g

 

위 정규식은 숫자를 끊어읽기 위해 세자리수마다 쉼표를 찍게합니다.

 

살펴보면 다음과 같습니다.

왼쪽에 숫자가 하나 존재하고,

오른쪽에 있는 숫자의 개수가 3의 배수인 경우입니다.

(+는 하나 그 이상 반복함을 의미합니다.)

 

따라서 위의 문자열에 해당 정규식을 실행시키면

1,234,567,890라고 찍힙니다.

 

 

정리하면 다음과 같습니다.

(?<=.....) : 긍정형 룩비하인드 - 하위 표현식(..... 부분)이 왼쪽에 매치될 때

(?<!.....) : 부정형 룩비하인드 - 하위 표현식(..... 부분)이 왼쪽에 매치되지 않을 때

(?=.....) : 긍정형 룩어헤드 - 하위 표현식(..... 부분)이 오른쪽에 매치될 때

(?!.....) : 부정형 룩어헤드 - 하위 표현식(..... 부분)이 오른쪽에 매치되지 않을 때

긍정형(positive), 부정형(negative),

룩어비하인드(lookbehind), 룩어헤드(lookahead)

 

 

여기서 왼쪽과 오른쪽은 문자와 문자 사이라는 해석이 맞을 듯싶습니다.

(문자라기보다는 정규표현식이 다루는 원자(더 이상 쪼갤 수 없음)의 개념이겠지만...)

저는 이렇게 이해하였습니다.

 

예제 3번에서 '1,234'부분을 보면 원래 '1234'입니다.

여기서 1과 2사이를 기준으로 왼쪽은 숫자 하나(1)가 있고,

오른쪽은 숫자가 문자열 끝에서 3의 배수로 묶여있습니다.(234)

따라서 그 자리(1과 2사이)에 ','을 집어넣은 것입니다.

 

이처럼 문자와 문자 사이를 기준으로

왼쪽 혹은 오른쪽에 매치 혹은 매치 안됨을 점검하는 것이

룩어라운드(lookaround)인 듯싶습니다.

하지만 실제로 매치가 되는 것이 아니라 그 자리만을 알려줍니다.

그래서 'Jeffley'가 'NoSyu'가 된 것이 아니라 'NoSyuley'가 된 것입니다. (예제 2)

 

 

참고 예제

단어의 시작과 끝 : '(?<!\w)(?=\)', '(?<=\w)(?!\w)'

HTML <B>태그 : '<B>((?!</B>).)*</B>'

 

 

참조

정규 표현식 완전 해부와 실습 Page 99~110

by NoSyu | 2007/11/26 21:55 | in Programming | 트랙백 | 덧글(0)

트랙백 주소 : http://NoSyu.egloos.com/tb/3963510
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]

:         :

:

비공개 덧글

◀ 이전 페이지          다음 페이지 ▶