2007년 11월 26일
정규표현식 룩어라운드(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만 한다.'
따라서 다음과 같은 정규식을 실행시키면 다음과 같습니다.
![]()
바뀐 부분을 보면 '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 | 2007/11/26 21:55 | in Programming | 트랙백 | 덧글(0)















☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]