https://vi.stackexchange.com/a/818/227 의 답변과 유사하게 전역 명령을 사용할 수 있습니다.
이를 통해 vim에게 패턴과 일치하는 행을 검색 한 다음 명령을 수행하도록 지시 할 수 있습니다.
귀하의 경우 "Level N :"으로 시작하는 줄 앞에 텍스트를 추가하여 글로벌 명령이 될 수 있습니다.
:g/^Level \d:/{COMMANDS}
명령에 대체 명령 (정규 표현식 대체) 사용
명령이 더 재미 있습니다. 변수를 사용하기 쉽기 때문에 보통 이런 식으로 정규 표현식을 대체하고 싶습니다.
질문의 예
:let i = 1 | g/^Level \d:/s/^/\=printf("%02d ", i)/ | let i = i+1
작동 원리
대체 명령의 대체 섹션에서 표현식이 될 수 있습니다.
가장 먼저 할 일은 변수 i
를 시작 번호로 설정하는 것 입니다. 나는 1을 선택했지만 아무 숫자 나 할 것입니다.let i = 1
그런 다음 전역 명령을 실행하여 일치하는 행에서 작업을 수행하도록 설정합니다. g/^Level \d:/
전역 명령이 값을 삽입하고 치환 명령과 let 명령을 사용하여 카운터를 증가시킵니다.s/^/\=printf("%02d ", i)/ | let i = i+1
대치 명령의 정규식은 줄의 시작 부분을 찾아서 식으로 ^
대체하며 식은 형식화 된 인쇄의 결과입니다. C 언어와 마찬가지로 vim의 printf는 형식 매개 변수를 사용합니다. %02d
는 인수가 10 진수 인 것처럼 변환하며 d
, 최소 2 개의 공백을 차지하고 2
0으로 채워 0
집니다. 자세한 내용 및 기타 변환 옵션 (부동 소수점 서식 포함)은을 참조하십시오 :help printf
. printf에 카운팅 변수 i
를주고 01
처음, 02
두 번째 등을줍니다. 이것은 대체 명령에 의해 행의 시작 부분을 대체하여 시작 부분에 printf의 결과를 효과적으로 삽입하는 데 사용됩니다.
d : 뒤에 공백을 넣습니다 "%02d "
. 당신은 질문에 그것을 요구하지 않았고 (예제 출력을 보지 못했습니다), 숫자를 단어 "Level"과 분리하고 싶었습니다. printf에 주어진 문자열에서 공백을 제거하여 레벨에서 L 바로 옆에 숫자를 삽입하십시오.
마지막으로 let i = i + 1
각 교체 후 카운터 를 증가시킵니다.
이것은 일반적으로 다른 기준과 일치하는 라인 부분을 임의의 기능 데이터로 대체하는 데 적용 할 수 있습니다.
결합 된 일반 명령 사용
이것은 간단한 삽입이나 복잡한 편집에 좋습니다. 대체와 마찬가지로 전역을 사용하여 일치 시키지만 정규 표현식 대체 대신 사용자가 입력 한 것처럼 일련의 작업을 실행합니다.
질문의 예
:let i = 1 | g/^Level \d:/execute "normal! I" . printf("%02d ", i) | let i = i+1
작동 원리
사용 된 값은 대체와 매우 유사하지만 (여전히 printf를 사용하여 숫자를 2 자리 숫자로 채우도록 숫자를 형식화합니다) 작업이 다릅니다.
여기에서는 문자열을 가져 와서 문자열을 ex 명령 ( :help :exe
) 으로 실행하는 execute 명령을 사용합니다 . "normal! I"과 데이터를 결합한 문자열을 생성합니다.이 데이터는 "normal! I01"과 "normal! I02"등입니다.
이 normal
명령은 일반 모드 에서처럼 작업을 수행합니다. 이 예에서 일반 명령은입니다 I
. 이는 행의 시작 부분에 삽입됩니다. 우리가 dd
그것을 사용했다면 라인을 삭제 o
하고 일치하는 라인 다음에 새로운 라인을 열 것입니다. 마치 I
일반 모드에서 직접 입력 한 것 (또는 다른 작업)과 같습니다. !
after normal
를 사용하여 매핑이 방해받지 않도록합니다. 참조하십시오 :help :normal
.
대체를 사용하는 첫 번째 예와 같이 printf의 값이 삽입됩니다.
이 방법은 정규식보다 더 빠를 수 있습니다 execute "normal! ^2wy" . i . "th$p"
. 텍스트의 시작 부분으로 ^
이동하고, 2 단어 앞으로 이동하고 2w
, i 번째 'h'문자가 될 때까지 잡아 당기고 y" . i . "th
, 줄의 끝으로 이동하여 $
붙여 넣기와 같은 작업을 수행 할 수 있기 때문 p
입니다.
이것은 매크로를 실행하는 것과 거의 비슷하지만 실제로 레지스터를 사용하지 않으며 모든 표현식의 문자열을 결합 할 수 있습니다. 나는 이것이 매우 강력하다는 것을 알았습니다.
각 레벨에 자체 카운터가있는 방법
각 레벨에 자체 카운터를 갖기를 원할 수 있습니다. 미리 최대 레벨 수를 알고 있다면 다음을 수행 할 수 있습니다 (최대 레벨을 찾기 위해 추가 코드를 추가하는 것은 어렵지 않지만이 답변을 너무 길게 만들 수 있습니다.
먼저, 정수로 이미 사용한 경우에는 i를 해제하십시오. 우리는 i를 목록으로 변환 할 수 없습니다. 그런 식으로 만들어야합니다.
:unlet! i
다음으로, i를 레벨 수를 포함하는 목록으로 설정하십시오. 당신은 당신의 질문에 2를 보여 주었지만, 재미로 10을 가정 할 수 있습니다. 목록 인덱싱은 0 기반이며 목록과 같은 1 기반 수정을 귀찮게하고 싶지 않기 때문에 충분한 요소 (11)를 만들고 0 인덱스를 사용하지 않습니다.
:let j = 0
:let i = []
:while j < 11 | let i += [1] | let j += 1 | endwhile
다음으로 레벨 번호를 얻는 방법이 필요합니다. 다행스럽게도 대용은 함수로도 사용할 수 있으므로 라인을 제공하고 레벨 번호를 추출합니다.substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")
i는 이제 11 1
의 목록이므로 (각 인덱스는 레벨에 대한 카운터 임) 이제이 대체 결과를 사용하도록 위의 예 중 하나를 조정할 수 있습니다.
대체 명령을 통해 :
:unlet! i | unlet! j | let j = 0 | let i = [] | while j < 11 | let i += [1] | let j += 1 | endwhile
:g/^Level \d:/let ind=str2nr(substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")) | s/^/\=printf("%02d ", i[ind])/ | let i[ind] += 1
일반 명령을 통해 :
:unlet! i | unlet! j | let j = 0 | let i = [] | while j < 11 | let i += [1] | let j += 1 | endwhile
:g/^Level \d:/let ind=str2nr(substitute(getline("."), "^Level \\(\\d\\):.*", "\\=submatch(1)", "")) | execute "normal! I" . printf("%02d ", i[ind]) | let i[ind] += 1
입력 예 :
Level 1: stuff
Level 1: Stuff
Some text
Level 3: Other
Level 1: Meh
Level 2: More
출력 예 :
01 Level 1: stuff
02 Level 1: Stuff
Some text
01 Level 3: Other
03 Level 1: Meh
01 Level 2: More