정규표현식 Lookahead, Lookbehind 기능 이해하기

개요

Lookahead, Lookbehind 기능은 다소 고급 문법에 속합니다. 자 일단 선 요약하면 다음과 같습니다.

패턴타입matches
X(?=Y)Positive lookaheadX if followed by Y
X(?!Y)Negative lookaheadX if not followed by Y
(?<=Y)XPositive lookbehindX if after Y
(?<!Y)XNegative lookbehindX 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가 등장하니까, 이미 결과에 포함된 는 찾지 못합니다. 아래 이미지를 참고해주세요.

3개에 하나씩 차례대로 소모되는 예제

숫자를 comma 로 포맷팅하는 예제

조금 더 복잡한 예제를 확인해봅시다. 만약 큰 숫자를 콤마로 포맷팅하고 싶다고 가정합시다. 예를 들어 12345671,234,567로 만들고 싶습니다. 아이디어를 말로 설명하면 간단합니다. 각각의 숫자에 대해 그 위치가 끝에서 3n+1 에 위치하는 숫자를 뽑아내어 그 숫자 뒤에 ,를 붙이는 것이죠. 즉 14 를 뽑아내면 됩니다! 그럴려면 아래와 같이 하면 됩니다.

(\d)(?=(\d{3})+(?!\d))

무슨 뜻인지 봅시다. \d는 숫자를 의미합니다. [0-9]와 의미가 똑같습니다.

  1. 우선 (\d) 로 숫자 하나를 잡습니다. 우선 모든 숫자에 대응이 됩니다.
  2. 이제 조건을 봅시다. 바로 뒤에 따라오는 커다란 (?= 묶음이 보이시죠? 저거는 Positive lookahead 에 의미하고, 추후 결과에서 제외됩니다.
  3. (\d{3})+ 는 숫자 3개 묶음이 1개 이상 나와야 한다는 의미입니다. 이제 1234 가 결과에 포함이 되었습니다.
  4. 뒤에서 딱 나누어 떨어지는지를 체크하기 위해 (?!\d) 로 가장 뒤에 숫자가 없는 경우에만 결과에 포함되도록 제한했습니다. 이제 1, 4 가 결과에 포함되었습니다.
숫자에 콤마를 삽입하는 예제

가장 위의 (\d)(?=(\d{3})+(?!\d)) 가 정규식이고, 우리가 테스트하고자 하는 텍스트는 1234567이며, 이 텍스트에 대해서 $1, 로 치환하겠다는 뜻입니다. $1이란 첫 번째 그룹을 의미하므로 위 정규식에서 (/d)에 해당합니다. 그렇게 되면 결과가 1,234,567이 되었다는 것을 확인할 수 있습니다. 어떤가요?!

3 thoughts on “정규표현식 Lookahead, Lookbehind 기능 이해하기

  1. 문자열 코딩문제를 풀다가, Positive Lookahead와 Negative Lookahead의 개념이 궁금해져 방문하게 되었습니다. 굉장히 도움이 많이 되었습니다. 감사합니다!

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다

Scroll to top