[vim] Vim에서 여러 줄 (두 블록) 병합

Vim에서 두 줄의 블록을 병합하고 싶습니다. 즉, 줄을 가져 와서 줄 n..m에 추가합니다 a..b. 의사 코드 설명을 선호하는 경우 :[a[i] + b[i] for i in min(len(a), len(b))]

예:

abc
def
...

123
45
...

되어야한다

abc123
def45

복사하여 붙여 넣기를 수동으로 수행하지 않고이 작업을 수행 할 수있는 좋은 방법이 있습니까?



답변

블록 모드 선택을 사용하여 단일 복사 / 붙여 넣기 로이 모든 작업을 수행 할 수는 있지만 원하는 것은 아닙니다.

Ex 명령 만으로이 작업을 수행하려면

:5,8del | let l=split(@") | 1,4s/$/\=remove(l,0)/

변형 될 것이다

work it
make it
do it
makes us
harder
better
faster
stronger
~

으로

work it harder
make it better
do it faster
makes us stronger
~

업데이트 : 이 많은 투표에 대한 답변은보다 철저한 설명이 필요합니다.

Vim에서 파이프 문자 ( |)를 사용하여 여러 Ex 명령 을 연결할 수 있으므로 위의 내용은

:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/

많은 Ex 명령은 여러 행을 접두사 인수로 받아들입니다. 위의 경우 5,8before del1,4before s///는 명령이 작동하는 행을 지정합니다.

del주어진 줄을 삭제합니다. 레지스터 인수를 사용할 수 있지만 하나를 지정하지 않으면 @"일반 모드에서 삭제하는 것처럼 행을 이름이 지정되지 않은 레지스터에 덤프합니다 . let l=split(@")그런 다음 기본 구분 기호 인 공백을 사용하여 삭제 된 행을 목록으로 분할합니다. 삭제 된 줄에 공백이있는 입력에서 올바르게 작동하려면 다음과 같이하십시오.

more than
hour
our
never
ever
after
work is
over
~

“work is”가 두 개의 목록 요소로 분리되지 않도록하려면 다른 구분 기호를 지정해야합니다 let l=split(@","\n").

마지막으로, 치환 s/$/\=remove(l,0)/에서 각 줄의 끝 ( $)을 expression의 값으로 바꿉니다 remove(l,0). remove(l,0)목록을 변경하여 l첫 번째 요소를 삭제하고 반환합니다. 이렇게하면 삭제 된 줄을 읽은 순서대로 바꿀 수 있습니다. 대신을 사용하여 삭제 된 줄을 역순으로 바꿀 수 remove(l,-1)있습니다.


답변

이 문제를 해결 우아하고 간결한 전 명령을 조합하여 얻을 수있다 :global, :move그리고 :join명령. 첫 번째 라인 블록이 버퍼의 첫 번째 라인에서 시작하고 커서가 두 번째 블록의 첫 번째 라인 바로 앞에있는 라인에 있다고 가정하면 명령은 다음과 같습니다.

:1,g/^/''+m.|-j!

이 기술에 대한 자세한 설명은 비슷한 질문 ” Vim paste -d ”동작에 대한 내 대답 을 참조하십시오 . ”.


답변

라인 블록을 결합하려면 다음 단계를 수행해야합니다.

  1. 세 번째 줄로 이동하십시오. jj
  2. 비주얼 블록 모드로 들어가십시오 : CTRL-v
  3. 줄 끝까지 커서를 고정합니다 (길이가 다른 줄에 중요). $
  4. 끝으로 가십시오 : CTRL-END
  5. 블록을 잘라 : x
  6. 첫 번째 줄의 끝으로 이동하십시오. kk$
  7. 여기에 블록을 붙여 넣습니다. p

운동은 최고는 아니지만 (나는 전문가가 아닙니다) 원하는대로 작동합니다. 더 짧은 버전이 있기를 바랍니다.

다음은 전제 조건이므로이 기술이 효과적입니다.

  • 시작 블록의 모든 줄 (문제의 예에서 abcdef)은 길이가 XOR입니다.
  • 시작 블록의 첫 번째 줄이 가장 길며 그 사이에 추가 공백은 신경 쓰지 않습니다.) XOR
  • 시작 블록의 첫 번째 줄은 가장 길지 않으며 끝에 공백이 추가됩니다.

답변

다음은 내가하는 방법입니다 (첫 번째 줄에 커서로).

qama:5<CR>y$'a$p:5<CR>dd'ajq3@a

두 가지를 알아야합니다.

  • 두 번째 그룹의 첫 번째 줄이 시작되는 줄 번호 (필자의 경우 5)
  • 각 그룹의 줄 수 (내 예에서는 3).

진행중인 작업은 다음과 같습니다.

  • qaq에서 “버퍼”에 다음까지 모든 것을 기록 a합니다.
  • ma 현재 줄에 마크를 만듭니다.
  • :5<CR> 다음 그룹으로갑니다.
  • y$ 줄의 나머지를 잡아 당깁니다.
  • 'a 이전에 설정된 마크로 돌아갑니다.
  • $p 줄 끝에 붙여 넣습니다.
  • :5<CR> 두 번째 그룹의 첫 번째 줄로 돌아갑니다.
  • dd 삭제합니다.
  • 'a 마크로 돌아갑니다.
  • jq 한 줄 아래로 내려 가서 녹음을 중지합니다.
  • 3@a 각 줄에 대해 작업을 반복합니다 (필자의 경우 3)

답변

다른 곳에서 언급했듯이 블록 선택은 갈 길입니다. 그러나 다음과 같은 변형을 사용할 수도 있습니다.

:!tail -n -6 % | paste -d '\0' % - | head -n 5

이 방법은 UNIX 명령 행에 의존합니다. paste유틸리티 라인 병합 이런 종류의를 처리하기 위해 만들어졌다.

PASTE(1)                  BSD General Commands Manual                 PASTE(1)

NAME
     paste -- merge corresponding or subsequent lines of files

SYNOPSIS
     paste [-s] [-d list] file ...

DESCRIPTION
     The paste utility concatenates the corresponding lines of the given input files, replacing all but the last file's newline characters with a single tab character,
     and writes the resulting lines to standard output.  If end-of-file is reached on an input file while other input files still contain data, the file is treated as if
     it were an endless source of empty lines.


답변

샘플 데이터는 램프와 동일합니다.

:1,4s/$/\=getline(line('.')+4)/ | 5,8d


답변

나는 그것을 너무 복잡하게 생각하지 않을 것입니다. 방금 virtualedit을
( :set virtualedit=all)
Select 블록 123과 아래에 설정하십시오.
첫 번째 열 뒤에 넣습니다.

abc    123
def    45
...    ...

1 사이의 여러 공간을 제거하십시오.

:%s/\s\{2,}/ /g