Introduce

regular expression에는 negative lookbehind 라는게 있습니다. 그 전에, 개념을 먼저 살펴봐야겠죠. 정규 표현식에는 lookbehind와 lookahead라는게 있습니다.

  • lookahead - 찾으려는 문자열의 이후에 위치하는 문자열을 뜻합니다.
  • lookbehind - 찾으려는 문자열의 이전에 위치하는 문자열을 뜻합니다.

예를 들어, 다음의 문자열이 있습니다.

aaabbbccc, dddbbbeee

그리고 eee로 끝나지 않는 bbb를 찾는다고 합시다.  단순히, bbb로 검색한다면 두 문자열의 bbb가 모두 찾아질 것 입니다. 그렇다면 우리는 ccc로 끝나는 bbb를 찾거나, eee로 끝나지 않는 bbb를 찾아야 합니다. 앞의 경우에 사용하는 검색 조건을 lookahead, 후자의 경우를 negative lookahead라고 합니다.

감을 잡으셨겠지만, lookbehind는 기준을 앞의 문자열에 두고 찾는 방법입니다. 즉, aaa로 시작되는 bbb를 찾거나, 반대로 ddd가 아닌 문자열로 시작되는 bbb를 찾을 수 있습니다. 이러한 방법을 lookbehind, negative lookbehind라고 부릅니다.

이러한 lookahead는 regular expression이 구현된 언어마다 조금씩 다른 문법형태를 가집니다. 오늘은 python과 javascript로 살펴 볼 생각입니다.

Lookahead & Lookbehind in python

python으로 표현하자면 다음과 같습니다.

[gist id="0997ec2a72b598c95114"]

lookahead나 lookbehind의 특징은 대상 문자열을 결과로 포함지 않는데 있습니다. 즉, 검사 대상이나 결과 대상은 아닌 문자열을 표현할 때 사용하시면 되겠습니다. python의 문법을 정리하면 다음과 같습니다. 이런 정리는 사실, reference page에 더 잘 나와 있습니다.

  • (?=pattern) - lookahead
  • (?!patten) - negative lookahead
  • (?<=pattern) - lookbehind
  • (?<!pattern) - negative lookbehind

Lookahead & Lookbehind in javascript

python과 똑같이 sample code를 살펴보겠습니다.

[gist id="8cf8b4d7d5d176e5fa16"]

음...? lookbehind에서 Invalid regular expression이라는 에러 메세지를 보여줍니다. javascript에는 lookbehind가 구현되어 있지 않기 때문입니다. 그럼, 사용할 수 없는걸까요?

python을 설명 드리면서, 검색 대상과 결과 대상을 구분하였습니다. 즉, lookbehind가 없더라도, 결과 대상을 다르게 취급한다면 우리는 lookbehind처럼 사용할 수 있다는 뜻이 되겠습니다. regular expression에서 부분 집합을 구하기 위해 사용되는 group 개념을 이용해서, 결과를 만들 때 group을 포함시키는 형태로 작성하면 되겠습니다.

[gist id="773c662407bfb24d1430"]

lookbehind_replace.js는 이렇게 찾은 문자열을 치환한다고 생각할 때, 위와 같이 작성할 수 있습니다. 자주 사용하신다면, prototype을 이용하는 방법도 있습니다. string 자체에 lookbehind를 지원하는 새로운 method를 추가하여, 작동하도록 고쳐쓸 수도 있겠죠. 보시다시피, 완벽하게 거를 수 있는 code 아니기에, 사용하실 때에는 주의가 필요할 것 같네요.

사실, 이 글을  작성한 이유는 javascript에 대한 내용을 정리하기 위함입니다. 언어에 lookahead나 lookbehind가 없다고 당황하지 마시고, 조금만 이해를 넓히시면 다른 방법으로도 같은 효과를 낼 수 있습니다. 단순한 code 조각이지만, 깔끔하고 전달하는 바가 분명하여 이렇게 블로깅까지 하게 되었네요. 정말, 세상에는 똑똑한 사람들이 많아요. ^^

Reference