tools/vim

Learn The Vimscript The Hard Way - 31. Basic Regular Expressions

seul chan 2020. 4. 8. 00:56

Basic Regular Expressions

Vim은 기본적으로 텍스트 에디터이다. 즉, 당신의 vimscript 코드는 text를 처리하는데 많은 일을 할 것이라는 말이다.

다음 예시를 적어보자 (복붙)

max = 10

print "Starting"

for i in range(max):
    print "Counter:", i

print "Done"

위 예시는 파이썬 코드인데, regex를 연습할 예제이기 때문에 파이썬을 몰라도 상관 없다.

여기서는 기본적인 정규표현식을 알고 있다고 가정하고 설명한다. 혹시 정규표현식을 잘 모른다면 Learn Regex the Hard Way 책을 읽으라고 추천하고 있다. (learn regex the easy way도 참고할 만 하다)

Highlighting

본격적으로 시작하기 전에, vim의 search highlighting 기능을 켜서 우리가 무엇을 하는지 확인할 수 있도록 하자

:set hlsearch incsearch

hlsearch는 검색을 시행했을 때 매칭되는 부분을 하이라이트 처리해주는 기능이며, incsearch는 검색 패턴을 작성하는 중에 해당 부분을 하이라이트 해주는 기능이다.

Searching

파일의 맨 위로 커서를 올린 후에 다음 명령어를 실행해보자.

/print

각각 알파벳을 적는 도중에도 vim은 매칭되는 문자를 하이라이트 해서 보여준다. 엔터를 치면 가장 먼저 발견한 print로 커서가 이동한다.

이제 다음 명령어를 실행해보자

:execute "normal! gg/print\<cr>"

위에서 검색했던 것과 동일한 기능을 수행한다. :execute "normal! ..." 명령어를 모르겠다면 이전 장을 참고.

다음번에 나오는 print를 찾고 싶아보자.

:execute "normal! gg/print\<cr>n"

print를 찾아 하이라이팅 하는 것은 똑같지만 커서가 두 번 째 print에 가 있는 것을 볼 수 있다.

이제 반대 방향으로 찾아보자.

:execute "normal! G?print\<cr>"

G로 파일의 가장 마지막으로 이동한 후 ?로 역방향 검색을 시행하였다.

Magic

/? 명령어는 사실 일반적인 알파벳 말고 정규표현식을 받을 수 있다.

:execute "normal! gg/for .+ in .+:\<cr>"

패턴을 찾을 수 없다고 나온다. 왜 안 되는걸까? 다음 명령어를 실행시켜보자.

:execute "normal! gg/for .\\+ in .\\+:\<cr>"

이제 찾고자 하는 for문 라인을 하이라이트 해준다. 무슨 차이가 있었는지 한 번 생각해보자.

두 가지 이유가 있다.

  • 첫째로 execute는 string을 받기 때문에 backslach(\)를 사용하려면 연속된 backslash를 사용하여야 한다. (\\)
  • 두번째로, vim에는 4가지 종류의 "다른" 정규표현식 파싱 모드가 존재한다. 기본 모드는 + 문자 (1개나 더 많은 캐릭터) 앞에 backslach가 필요하다.

vim에서 검색을 바로 하면 이를 더 쉽게 알아볼 수 있다.

/print .+

/print .\+

\+를 사용하여야 실제로 검색이 되는 것을 볼 수 있다.

Literal Strings

앞의 String에서 살펴본 것처럼 vim은 작은따옴표를 "literal string"으로 인식하여 해당 문자를 그대로 반환한다. 예를들어, 'a\nb'는 해당 문자 그대로를 반환한다.

이 literal string을 사용하는 것이 double backslash를 사용하는 것을 해결해 줄 수 있을까? 이 문제에 대한 답은 생각보다 복잡하기 때문에 잠시 생각하는 시간을 가져보자.

작은따옴표와 single backslash를 가진 다음 명령어를 실행시켜보자.

:exexute 'normal! gg/for .\+ in .\+:\<cr>'

gg를 실행시켜 파일의 맨 위로 이동하긴 하지만 검색은 되지 않는 것을 볼 수 있다.

위의 명령어는 \<cr>이 엔터키 대신에 그냥 문자열로 해석되어 실행되지 않는다.

하지만 아직 희망을 잃지 말아라! (?!) vim은 string concat을 허용하기 때문에 해당 문자를 나눠 적으면 된다

:execute "normal! gg" . '/for .\+ in .\+:' . "\<cr>"

이제 예상했던대로 검색이 되는 것을 볼 수 있다.

Very Magic

이제 앞서 말한 vimscript의 4가지 regex parsing 모드가 뭔지 궁금해 할 것이다.

:execute "normal! gg" . '/\vfor .+ in .+:' . "\<cr>"

위 예시는 regex 패턴 앞에 \v가 추가되어있다. 이는 vim에게 "very magic" regex parsing mode를 사용하게 하여 다른 프로그래밍 언어 (python ,ruby, perl)와 비슷하게 정규표현식을 사용할 수 있게 해준다.

Exercises

  • Read :help magic carefully.

총 네 가지 magic 모드가 있다. 보통은 \m (magic) 모드로 동작.

after:      \v       \m        \M         \V        matches ~
        'magic' 'nomagic'
      $       $        $         \$        matches end-of-line
      .       .        \.         \.        matches any character
      *       *        \*         \*        any number of the previous atom
      ~       ~        \~         \~        latest substitute string
      ()       \(\)     \(\)     \(\)    grouping into an atom
      |       \|        \|         \|        separating alternatives
      \a       \a        \a         \a        alphabetic character
      \\       \\        \\         \\        literal backslash
      \.       \.        .         .        literal dot
      \{       {        {         {        literal '{'
      a       a        a         a        literal 'a'
  • Read :help pattern-overview to see the kinds of things Vim regexes support. Stop reading after the character classes.

img

  • Read :help :match. Try running the :match Error /\v.../ command a few times by hand.

해당 그룹을 특정 하이라이팅 해주는 기능. 테스트 이후 모두 없애고 싶으면 :match None을 입력하면 된다.

Error 그룹은 이미 만들어진 highlight인듯. 다음 예시는 72자 이상의 경우 Error 매칭하게 하는 예시

:match Error /.\%>72v/
  • Edit your ~/.vimrc file to add a mapping that will use match to highlight trailing whitespace as an error. A good key to use might be w.
:match Error /\v.\s$/
" 굳이 very magic을 사용하지 않아도 된다
:match Error /.\s$/

" mapping 추가
nnoremap <leader>w :match Error /.\s$/<CR>
  • Add another mapping that will clear the match (perhaps W).
nnoremap <leader>W :match None<CR>
  • Add a normal mode mapping that will automatically insert the \v for you whenever you begin a search. If you're stuck remember that Vim's mappings are extremely simple and you just need to tell it which keys to press when you use the mapped key.

(아래 방법이 맞는지 잘 모르겠지만)

:nnoremap / /\v
  • Add the hlsearch and incsearch options to your ~/.vimrc file, set however you prefer.

개인적으로는 항상 넣어서 사용하는 설정들이다.

:set hlsearch
:set incsearch
  • Read :help nohlsearch. Note that this is a command and not the "off mode" setting of hlsearch!

hlsearch 옵션을 끄는 것이 아니라 해당 하이라이팅만 꺼준다. 개인적으로 검색 이후 하이라이팅을 제거하기 위해 자주 사용하는 코멘드이다. (:noh)

  • Add a mapping to "stop highlighting items from the last search" to your ~/.vimrc file.
nnoremap <leader>nh :nohlsearch<CR>