개요
Lookahead, Lookbehind 기능은 다소 고급 문법에 속합니다. 자 일단 선 요약하면 다음과 같습니다.
패턴 | 타입 | matches |
---|---|---|
X(?=Y) | Positive lookahead | X if followed by Y |
X(?!Y) | Negative lookahead | X if not followed by Y |
(?<=Y)X | Positive lookbehind | X if after Y |
(?<!Y)X | Negative lookbehind | X if not after Y |
이러한 기능을 모아서 Lookaround 라고 합니다. 본 기능이 동작하는 방식은, 이해하기 쉽게 설명을 하자면, 본래 패턴에 맞는 곳을 우선 찾고, 그 다음 추가적으로 해당 Lookaround 의 조건이 맞는지 아닌지를 체크합니다. 그 다음 Positive 이냐, Negative 이냐에 따라서 결과를 포함시키거나 제외시킵니다. Positive 는 조건 Y 가 만족한다면 매칭 결과에 그대로 포함시킨다는 것입니다. 즉 조건 Y가 충족하지 않는다면 매칭 결과에 포함이 되지 않겠죠. Negative 는 조건 Y 가 만족한다면 매칭 결과에서 제외시킵니다. 즉 조건 Y가 충족하지 않는다면 매칭 결과에 포함이 될 것입니다. Positive 와 Negative 는 정 반대로 동작합니다.
Lookahead와 Lookbehind 의 차이점은 간단합니다. Lookahead 는 꼬리말(suffix)을 확인하는 용도이고, Lookbehind는 머리말(prefix)를 확인하는 용도입니다. 말이 약간 거꾸로 되어 있지요? 실제 문법 상으로는 <
가 포함되어 있냐 그렇지 않냐로 구분할 수 있습니다. <
방향이 왼쪽이니까 앞쪽이라고 기억하고 있으면 될 것 같습니다.
일반적으로는 간단히 결과를 제외시키고 싶을 때 Negative Lookaround 로 하여 많이 사용합니다. (참고, 스택 오버플로우)
한 가지 특징으로는, Lookaround 기능은 그 결과가 소모되지 않습니다. 즉 조건이 겹칠 필요가 있을 때 유용하게 사용될 수 있다는 것입니다. 이는 예제를 보면서 한번 같이 확인해보도록 합시다.
결과가 소모되지 않는 예제
아래 두 개의 이미지 결과 차이로 확인할 수 있습니다. 첫번째 예제는 (?<=마마마)
를 A
로 바꾸는 예제입니다. 여기서 놀라운 점은 결과로 아무것도 잡히지 않는다는 것입니다. 결과로는 오로지 해당 위치를 가리키는 정보만 있을 뿐이지 (마마마가 연속해서 등장하는 바로 뒤자리) 실제로 찾는 값은 없습니다. 없는 걸 치환하니까, 결국엔 새롭게 A
가 생깁니다.
반면 마마마
를 통째로 찾고 마마마A
로 바꾼다면 우선 마마마
가 소모됩니다. 마마마
가 사라지고 대신에 마마마A
가 등장하니까, 이미 결과에 포함된 마
는 찾지 못합니다. 아래 이미지를 참고해주세요.
숫자를 comma 로 포맷팅하는 예제
조금 더 복잡한 예제를 확인해봅시다. 만약 큰 숫자를 콤마로 포맷팅하고 싶다고 가정합시다. 예를 들어 1234567
을 1,234,567
로 만들고 싶습니다. 아이디어를 말로 설명하면 간단합니다. 각각의 숫자에 대해 그 위치가 끝에서 3n+1 에 위치하는 숫자를 뽑아내어 그 숫자 뒤에 ,
를 붙이는 것이죠. 즉 1
과 4
를 뽑아내면 됩니다! 그럴려면 아래와 같이 하면 됩니다.
(\d)(?=(\d{3})+(?!\d))
무슨 뜻인지 봅시다. \d
는 숫자를 의미합니다. [0-9]
와 의미가 똑같습니다.
- 우선
(\d)
로 숫자 하나를 잡습니다. 우선 모든 숫자에 대응이 됩니다. - 이제 조건을 봅시다. 바로 뒤에 따라오는 커다란
(?=
묶음이 보이시죠? 저거는 Positive lookahead 에 의미하고, 추후 결과에서 제외됩니다. (\d{3})+
는 숫자 3개 묶음이 1개 이상 나와야 한다는 의미입니다. 이제1234
가 결과에 포함이 되었습니다.- 뒤에서 딱 나누어 떨어지는지를 체크하기 위해
(?!\d)
로 가장 뒤에 숫자가 없는 경우에만 결과에 포함되도록 제한했습니다. 이제1
,4
가 결과에 포함되었습니다.
가장 위의 (\d)(?=(\d{3})+(?!\d))
가 정규식이고, 우리가 테스트하고자 하는 텍스트는 1234567
이며, 이 텍스트에 대해서 $1,
로 치환하겠다는 뜻입니다. $1
이란 첫 번째 그룹을 의미하므로 위 정규식에서 (/d)
에 해당합니다. 그렇게 되면 결과가 1,234,567
이 되었다는 것을 확인할 수 있습니다. 어떤가요?!
번역본 같은데 해석이 너무 부자연스럽습니다…
님 뇌 해석이 부자연스러운거 같은데
문자열 코딩문제를 풀다가, Positive Lookahead와 Negative Lookahead의 개념이 궁금해져 방문하게 되었습니다. 굉장히 도움이 많이 되었습니다. 감사합니다!