지난 글에서 notepad++에서 특정 패턴에 매칭되는 영역만 추출하는 방법에 대해 소개하였는데요, 이번에는 vim에서 같은 기능을 어떻게 구현할 수 있는지에 대해서 알아보겠습니다.
:s/{pattern}/\=
버퍼 내의 텍스트를 치환하는 :s
명령에서, 패턴 다음에 오는 치환할 문자열 부분이 \= 으로 시작하는 경우에는 이 영역이 표현식(expression)으로서 평가됩니다. 만약 표현식을 평가한 결과가 리스트 타입인 경우에는 최종 결과는 개행 문자로 결합된 형태가 됩니다. 이 표현식 내부에서는 submatch()
함수가 매치된 텍스트를 얻는데 사용될 수 있습니다. 매치된 전체 영역은 submatch(0)
으로 표현하며, 만약 매치 패턴에 그룹을 지정했다면, 괄호 안에는 그룹의 번호가 들어갈 수 있습니다. 다음 명령에서는 setreg()
함수를 사용해서 치환할 부분을 평가하면서 검색된 패턴을 레지스터 a에 라인으로 추가합니다.
:let @a='' | %s/\v\d{8}-\d{7}/\=setreg('A', submatch(0), 'l')/gn | new | put! a
:s
명령에서 g
플래그는 한 라인에 하나 이상 매치가 있으면 모두 변경을 적용하는 것입니다. n
플래그는 매치에 대해서 치환을 적용하지 않고 스킵하는 플래그입니다. 또한 setreg()
함수에서는 레지스터에 설정한 값을 그대로 리턴하기 때문에, 결과적으로 이 명령을 실행하더라도 현재 버퍼에서 변경되는 내용은 없으며, 레지스터 a의 값에 매치될 내용들이 추가됩니다.
setreg() 함수
주어진 값을 지정한 레지스터에 저장하며, 그 값을 그대로 리턴합니다.
setreg({regname}, {value}[, {options}])
'c'
/'v'
: characterwise 모드'l'
/'V'
: linewise 모드'b'
or'<CTRL_V>'
: blockwise-visual 모드
이 때 옵션에 'a'
가 포함되어 있거나, 레지스터 이름이 대문자로 주어진다면 현재 레지스터의 내용을 변경하지 않고 추가하게 됩니다.
submatch() 함수
이 함수는 :s
명령이나, substitute()
함수 내부에서만 사용할 수 있는 명령으로, 패턴에 매칭된 부분에서 다시 하위 매치 그룹을 찾는 함수입니다. submatch(0)
과 같이 쓰면 패턴 전체에 일치하는 부분일 리턴하며, 1, 2..와 같은 번호를 사용하면 해당 번호의 그룹에 매치하는 영역을 리턴합니다.
: let @a='' | " 레지스터 a의 내용을 초기화
%s/\v\d{8}-\d{7}/ " 00000000-0000000 의 형식으로 된 부분을 찾음
\=setreg('A', submatch(0), 'l) " 찾은 부분을 레지스터a에 추가 (레지스터 이름을 대문자로 씀)
/gn | " 전체에 대해 실행하며, 매치 부분을 변경하지 않고 skip함
new | " 새 버퍼를 열기
put! a " 레지스터 a의 내용을 현재버퍼(새 버퍼)에 붙여넣음
사용자 정의 명령
매번 긴 명령어를 입력하기가 번거로우니, 마지막으로 검색한 패턴을 사용하여 매치되는 부분을 새 버퍼에 출력하도록 하는 함수를 작성하고, 이를 사용자 정의 명령으로 호출할 수 있도록 합니다. :substitute
명령을 실행할 때, 패턴 부분을 비워두면 마지막으로 사용한 검색 패턴을 재사용하게 됩니다.
vim9script
command -nargs=0 ExtractSearch ExtractSearchPattern()
def ExtractSearch()
if @/ == ''
return
endif
var temp = @a
@a = ''
silent :%s//\=setreg('A', submatch(0), 'al')/gn
new
put! a
normal! gg
nohls
@a = temp
enddef
참고로 이렇게 추출한 값 중에서 중복을 제거하려면 :sort u
를 실행하면 됩니다. :sort u
는 정렬한 후 연속되는 라인이 중복된 라인이라면 자동으로 삭제합니다. 만약 라인의 순서를 변경하지 않으면서 중복된 라인을 제거하려면 별도의 외부 프로그램이나 vim script로 작성한 커스텀 함수를 사용하는 등 다른 방법을 동원할 필요가 있습니다.