기술 관련/etc

정규식 Lookahead와 Lookbehaind

ID 홍차 2022. 5. 16. 22:21

정규식은 일정한 패턴을 이용하여 입력된 문자열 정보가 조건에 일치하는지 확인하거나 특정 조건에 맞추어 치환 할 때 주로 사용된다.

 

물론 정규식이 아니라도 프로그래밍과 같은 다양한 방식으로 이를 처리 할 수 있겠지만, 정규식을 이용하면 그 과정이 절차적인 방식보다 훨씬 간결해진다. 물론 입력 조건이 정규화된 형태가 아니거나 구문이 너무 복잡해서 최적화가 되지 않는 경우도 있지만 대부분의 경우는 상당히 효과적으로 사용 될 수 있다.

 

정규식은 Regular Expression 으로 정규 표현식이 바른 표현이지만 줄여서 정규식(Regex)이라 부른다. 정규 표현식에 대한 상세 내용은 https://ko.wikipedia.org/wiki/정규_표현식을 참고하면 될 듯 하고, 이 정규식 중에서 자주 사용할만한 구문인 lookahead와 lookbehind를 좀 더 상세하게 살펴 보고자 한다.

 

정규 표현식 - 위키백과, 우리 모두의 백과사전

노란색 강조 부분은 다음 정규식을 사용했을 때 매치된 것이다. 정규 표현식(正規表現式, 영어: regular expression, 간단히 regexp[1] 또는 regex, rational expression)[2][3] 또는 정규식(正規式)은 특정한 규칙

ko.wikipedia.org


문장 구분 분석에 주로 사용되긴 하지만 특정 조건에 맞는지를 확인하는 경우도 많이 사용한다. 예를 들어 "주어진 문자열에 B라는 문자가 포함되어 있는가" 와 같은 조건을 만족하는 정규식은 /[B]/ 를 이용 할 수 있다. 그렇다면, "주어진 문자열에 B라는 문자가 안포함되는가?"일 때는 어떻게 표현할까? 

정규식에서는 문자열 집합은 []을 사용하게 되는데 집합에 포함되지 않는 문자는 [^]를 사용할 수 있다. 따라서 /[^B]/로 표현하는 것을 고민해 볼 수 있다. 그러나, /[^B]/는 "B를 제외한 모든 문자"인 경우 참이된다. 즉, B로 시작하고 뒤에 다른 문자가 오거나, 다른 문자 뒤에 B가 오거나 심지어 아무것도 없는 공백 상태도 참이 된다. B만 아니면 될 뿐이다 :)

그래서 조건을 더 추가하여 다음과 같이 작성 할 수 있다.

/^[^B]*$/


이번에는 "B"와 같은 문자 하나가 아닌 문자열인 경우에 대해 생각해 보자. "주어진 문자열에서 abc라는 문자열이 포함되지 않는가?"

정규식을 /[^abc]/ 로 쓰면 되지 않을까하는 생각이 들지도 모르지만, 이는 "a 또는 b 또는 c를 제외한 모든 문자"이므로 의도했던 경우와 다르다. abc 문자열을 묶음으로 인식하도록 하는 것을 먼저 떠올릴 수 있는데, 정규식에서 제공하는 Negative Look Around 기능을 이용하여 조건을 만족 여부에 따라 매치를 결정 할 수 있다.

Negative Look Around 문법을 이용하여 앞서 조건을 표현하면 다음과 같이 작성 할 수 있다.

/^(.(?!abc))*$/

입력을 아래와 같이 하는 경우 글자의 배경이 파란색으로 표기되는 부분을 볼 수 있는데, 이는 위의 정규식과 매치되는 부분이다.

a
ab
abc
bc
aaabcc
bbbabc
cccabaab

위의 정규식은 Negative look ahead 방식을 이용한 것인데, Look around 방식에는 Look Ahread와 Look Behind 그리고 각각 조건의 만족 또는 불만족에 대한 Positive/ Negative를 조합하여 네 가지 방식의 Look around가 있다.

Negative Look Ahead X(?!Y)
X를 찾되 Y가 따라오지 않는 경우만 매치되는 것을 뜻한다.

Positive Look Ahead X(?=Y)
X를 찾되 Y가 따라붙는 경우에만 X에 대해 매치된다

Y의 입장에서 X가 앞쪽에 놓여 있기 때문에 Look ahead라는 표현을 쓰는것으로 보인다. Look ahead가 조건Y의 앞에 놓인 X를 바라 보는 경우라면, 뒤를 바라보게 하는 것도 있는데, 이를 Look behind라고 한다.

Positive Look Behind (?<=Y)X
Y의 뒤에 따라 붙는 X를 찾되 Y조건을 만족하는 경우만 매치된다.

Negative Look Behind (?<!Y)X
Y의 뒤에 따라 붙는 X를 찾되 Y조건을 만족하지 않는 경우만 매치된다.

사실, X가 앞에 있든지 뒤에 있던지에 따라 달라질 뿐이므로 앞서 Negative Look Ahead로 표현했던 /^(.(?!abc))*$/ 정규식을 Negative Look Behind로도 바꿀 수 있다.

/^((?<!abc).)*$/


단, JavaScript를 사용하는 경우 Look behind가 대부분의 Web Browser에서 지원하지 않는다고 하니, 사용에 주의 해야 한다.

* 참고 링크, https://javascript.info/regexp-lookahead-lookbehind

 

Lookahead and lookbehind

javascript.info