vim의 정규식 기호와 very magic 모드

vim의 문자열 검색, 치환 기능은 패턴 매칭에 의한 것이며, 이 패턴 매칭은 정규식에 기반을 두고 있다. 그런데 정규식 문법을 조금 알고 있는 상태에서 vim의 정규식을 사용하면 깊은 빡침을 느끼거나 심한 멀미를 겪을 수 있다. 예를 하나 들어보자.

(this)isnot{this}nor[this]

이런 문자열이 있다고 할 때, 괄호들을 포함한 this를 검색, 즉 (this), {this}, [this]를 검색하려면 다음의 패턴을 사용한다.

[\(\{\[]             : (, {, [ 은 각각 이스케이프되고, 그 중의 하나 
        this
            [\)\}\]] : ), }, ] 도 각각 이스케이프하여 그 중의 하나

사실 이 패턴은 (this} 같은 것도 찾기 때문에… 정확하게 하려면 (?:\(this\)|\{this\}|\[this\]) 으로 찾아야 한다.

만약 검색 자체에 사용할 패턴을 (this)라고 한다면 이 때는 그저 this 라는 단어를 찾아서 이를 캡쳐링 그룹으로 지정하는 것이기 때문에 괄호 기호 자체는 매칭에서 무시될 것이다.

vim 정규식의 배신

그런데 vim에서는 (this)라고 검색하면 어떻게 되는고 하니, 다음과 같이 검색돼 버린다.

배신도 이런 배신이 없다

 

그럼 [ ... ]를 사용해서 여러 글자 중에 한 글자를 구하는 패턴은? 이를 확인하기 위해서 [this 까지 검색해보면 vim은 엄청 태연하게 [문자를 “글자 그대로” 찾아주고 있다. 아니, 그럼 vim에서는 정규식 특수기호를 못쓰는 걸까?

이쯤되면 당황하기 시작한다

그런데 찾고자 하는 패턴이 [this]완성되면 기대했던(?) 바 대로 동작하기는 한다. 그런데 이게 더 당혹스럽다. 그러니까 vim의 정규식의 특수 기호는 좀 뭔가 다르게 쓰인다 이건가?

골치아픈 것이 vim에서는 (그것도 더 골치아픈 것은, “일부”) 특수 기호 문자들에 대해서 무조건 “문자 그대로의 의미”를 적용하게 된다. 이는 검색모드에서 검색을 구동했을 때 ‘문자 그대로를 찾는’ 것에 보다 충실하기 위해서라고 추측된다.  따라서 몇몇 문자들은 거꾸로 이스케이프하여 정규식 패턴내의 특수한 의미를 가지도록 해야 한다. 이렇게 차이가 있는 기호들에는 다음과 같은 것들이 있다.

심볼 정규식 의미 vim 정규식 의미
(, ) 캡쳐링 그룹을 만든다 그냥 괄호 문자에 해당한다
\(, \) 이스케이프된 괄호문자. 괄호 문자 그대로에 매칭한다. 캡쳐링 그룹을 만든다.
[, ] 다중 선택지 중 한 글자에 매칭한다. [abc 와 같이 패턴이 쓰여질 때는 [ 문자 그대로에 매칭한다. [abcd]로 쓰여질 때는 a, b, c, d 중 한글자에 매칭한다.
\[, \] 대괄호 문자 그대로에 매칭한다. 대괄호 문자 그대로에 매칭한다.
{. } 수량 범위 한정자로 동작한다. 중괄호 문자 그대로에 매칭한다.
\{, \} 중괄호 문자 그대로에 매칭한다. 수량 범위 한정자로 동작한다.
+ 특정패턴 뒤에 붙어서 1개 이상있음을 알리는 수량한정자. + 문자 그대로에 매칭한다.
\+ 이스케이프된 플러스 기호 문자. 수량한정자로 동작한다.
? 0개 혹은 1개를 의미하는 수량한정자 물음표 문자에 그대로 매칭한다.
\? 이스케이프된 물음표 수량한정자로 동작한다.
. 임의의 문자 1개에 대응 임의의 문자 1개에 대응
/ 문자 그대로의 슬래시 혹은 딜리미터 (정규식 마다 다름) 딜리미터로 동작
\/ 이스케이프된 딜리미터, 슬래시 문자 그대로에 매칭 슬래시 문자에 매칭
\ 역슬래시 문자. 이스케이프에 사용됨 단독으로 쓰인 경우에는 역슬래시 문자 그대로에 매칭.
\\ 이스케이프된 역슬래시문자. 역슬래시 문자 그대로에 매칭 역슬래시 문자 그대로에 매칭

vim에서만 정규식을 쓰고, 다른 곳에서는 정규식을 쓸 일이 없다면 모르겠는데, 이 부분은 여러모로 난감하고 짜증나는 일이 아닐 수 없다. 그렇지만 vim에서는 이에 대한 혼란을 피하기 위해서 매직 모드라는 걸 제공해주고 있다.

해결책 – magic mode

이를 머리속에서 이해하고 “해석된” 정규식을 사용하는 것은 매우 깊은 빡침을 선사하는 습관이 될 수 있다. 따라서 정규식 자체를 파싱할 때 숫자와 영문자가 아닌 모든 기호 문자를 정규식 문법의 특수 문자로 인식하도록 하는 “Very Magic”모드를 사용하면, 일반 에디터나 스크립트 언어에서 사용되는 정규식과 동일한 문법을 사용할 수 있다. 매직 모드는 다시 4가지로 분류되는데

  1. magic – ., $, * 등 몇 개의 심벌에 대해서만 특별한 의미를 유지한다.  (기본)
  2. nomagic – $ 를 제외한 모든 심벌은 문자 그대로로 해석된다.
  3. very magic – 거의 대부분의 심벌이 특수 의미를 가지며, 글자 그대로 해석하기 위해서는 이스케이프해야 한다.
  4. vary no magic – 모든 심벌은 글자 그대로로 해석되며, 특수한 의미를 가지기 위해서는 이스케이프해야 한다.

매직 모드를 선택하기 위해서는 패턴의 맨 앞에 \v, \m 을 넣으면 된다. \m 으로 시작하면 매직모드, \v 로 시작하면 very 매직 모드이다. 그리고 대문자는 각각의 no 매직 모드를 의미한다.  따라서 정규식 패턴을 여타 스크립트와 동일하게 쓰기 위해서는  very magic 모드를 사용하면 된다.

magic 모드의 관련된 설명은 vim 의 magic 항목에 대한 도움말을 찾아보면 된다. (:h magic) 또한 vimrc에 다음 한 두줄을 추가하여 기본적으로 모든 검색을 very magic 모드에서 수행하게 할 수 있다.

nnoremap / /\v
vnoremap / /\v