정규식 .+: 과 일치하는 문자열로 http: 가 리턴되었다. 만약 http:라는 검색 결과에서 : 을 제외하고 출력하려면 어떻게 해야할까?
위 예는 그나마 간단하지만 훨씩 복잡한 정규식이어서 그룹핑은 추가로 할 수 없다는 조건까지 더해진다면 어떻게 해야 할까?
이럴 때 사용할 수 있는 것이 바로 전방 탐색이다.
전방 탐색에는 긍정(Positive)과 부정(Negative)의 2종류가 있다.
(?=...) 긍정형 전방 탐색 - ...에 해당되는 정규식과 매치되어야 하며, 조건이 통과되어도 문자열이 소모되지 않는다.
(?!...) 부정형 전방 탐색 - ...에 해당되는 정규식과 매치되지 않아야 하며, 조건이 통과되어도 문자열이 소모되지 않는다.
긍정형 전방 탐색
정규식 중 :에 해당하는 부분에 긍정형 전방 탐색 기법이 적용되어 (?=:)으로 변경되었다. 이렇게 되면 기존 정규식과 검색에서는 동일한 효과를 발휘하지만 :에 대당되는 문자열이 정규식 엔진에 의해 소모되지 않아(검색에는 포함되지만 검색 결과에는 제외됨) 검색 결과에서는 :이 제거된 후 리턴되는 효과가 있다.
.*[.].*$
이 정규식은 파일명 + . + 확장자를 나타내는 정규식이다. 이 정규식은 foo.bar, autoexec.bat, sendmail.cf 같은 형식의 파일과 매치될 것이다. 이제 이 정규식에 "확장자가 bat인 파일은 제외해야 한다."는 조건을 추가해 보자. 가장 먼저 생각할 수 있는 정규식은 다음과 같을 것이다.
.*[.][^b].*$
이 정규식은 확장자가 b라는 문자로 시작하면 안 된다는 의미이다. 하지만 이 정규식은 foo.bar라는 파일마저 걸러내 버린다. 정규식을 다음과 같이 수정해보자.
.*[.]([^b]..|.[^a].|..[^t])$
이 정규식은 | 메타 문자를 사용하여 확장자의 첫 번째 문자가 b가 아니거나 두 번째 문자가 a가 아니거나 세 번째 문자가 t가 아닌 경우를 의미한다. 이 정규식에 의하여 foo.bar는 제외되지 않고 autoexec.bat은 제외되어 만족스러운 결과를 리턴한다. 하지만 이 정규식은 아쉽게도 sendmail.cf처럼 확장자의 문자 개수가 2개인 케이스를 포함하지 못 하는 오동작을 하기 시작한다.
위의 것을 다음과 같이 바꾸어야 한다.
.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$
확장자의 문자 개수가 2개여도 통과되는 정규식이 만들어졌다. 하지만 정규식은 점점 더 복잡해지고 이해하기 어려워진다.
그런데 여기서 bat 파일말고 exe파일도 제외하라는 조건이 추가로 생긴다면 어떻게 될까? 이 모든 조건을 만족하는 정규식을 구현하려면 패턴은 더욱 더 복잡해져야만 할 것이다.
부정형 전방 탐색
이러한 상황의 구원 투수는 바로 부정형 전방 탐색이다. 위 케이스는 부정형 전방 탐색을 사용하면 다음과 같이 간단하게 처리된다.
.*[.](?!bat$).*$
확장자가 bat가 아닌 경우에만 통과된다는 의미이다. bat라는 문자열이 있는지 조사하는 과정에서 문자열이 소모되지 않으므로 bat가 아니라고 판단되면 그 이후 정규식 매칭이 진행된다.
exe 역시 제외하라는 조건이 추가되더라도 다음과 같이 간단히 표현할 수 있다.
.*[.](?!bat$|exe$).*$
Example
긍정형 전방 탐색으로 .com, .net 이 아닌 것을 걸러내는 예제