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


323

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

예:

abc
def
...

123
45
...

되어야한다

abc123
def45

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


그래서 ... 교대로 연결하고 싶습니까? 즉, join과 line x을 결합 하고 싶 x+2습니까?
Larsks

1
아니요, 두 개의 별도 블록이 있습니다. [a[i] + b[i] for i in min(len(a), len(b))]
유사

2
비슷한 질문을 참조하십시오 (및 답변!) 여기
NWS

답변:


880

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

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)있습니다.


1
흠 ... 나는 엔터를 한 번만 누르면된다. 그리고 두 반쪽 사이에 공백을 삽입하지 않습니다. 줄에 후행 공간이 있으면 ( "work it"예제와 같이) 여전히 남아 있습니다. s/\s*$/대신을 사용하여 후행 공백을 제거 할 수 있습니다 s/$/.
rampion

1
설명 주셔서 감사합니다. :sil5,8del | let l=split(@") | sil1,4s/$/\=remove(l,0)/ | call histdel("/", -1) | nohls실행 후 검색 기록을 정리하므로 더 나은 것 같습니다. 그리고 Enter 키를 눌러야하는 "x more / less lines"메시지가 표시되지 않습니다.
ThiefMaster

11
당신이 그 답을 완벽하게 정력 참조를 원하는 경우 : :help range, :help :d, :help :let, :help split(), :help :s, :help :s\=, :help remove().
Benoit

16
당신 같은 사람들이 이와 같은 답변을 게시하고 있는지 확인하는 것은 내가 중재자가 된 이유입니다. Good show :)
Tim Post

1
처음 4 문장 이후에 공백이 없으면 문제가 있습니다.
Reman

58

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

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

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


E16: Invalid Range-그러나 어쨌든 작동합니다. 1,그것을 제거하면 오류없이 작동합니다.
ThiefMaster

그리고 너무 나쁘면 둘 이상의 답변을 받아 들일 수 없습니다. 그렇지 않으면 녹색 마크가 표시됩니다!
ThiefMaster

3
아주 좋아요! 나는 몰랐다:move 하고 :join!,도 무엇 ''범위 인수 (같은 의미 :help '') 무엇 +-범위 수정으로 의미 ( :help range). 감사!
rampion

@ThiefMaster :이 명령은 결합 할 두 줄 범위가 서로 인접 해있을 때 커서가 처음 두 번째 블록의 첫 번째 줄 바로 앞에 오는 첫 번째 블록의 마지막 줄에있을 때 사용되도록 설계되었습니다. (연결된 답변과 질문을 참조하십시오.) 명령은 블록의 줄 수가 다르더라도 오류 메시지를 표시하지만 의도 한대로 작동합니다. sil!명령 앞에 추가 하여 오류 메시지를 표시하지 않을 수 있습니다 .
ib.

2
@ib .:이 답변에 자세한 설명을 넣는 것도 좋은 생각이라고 생각합니다.
ThiefMaster

44

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

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

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

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

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

우와, 흥미 롭습니다! 나는 그것이 그렇게 될 것이라고 생각하지 않았을 것입니다.
voithos

13
때문에 만 원으로이 작품 abcdef같은 길이입니다. 블록 선택은 삭제 된 텍스트의 들여 쓰기를 유지하므로 텍스트를 넣을 때 커서가 짧은 줄에 있으면 줄이 더 긴 문자의 문자 사이에 삽입되고 커서가 더 길면 짧은 문자에 공백이 추가됩니다 하나.
이즈 카타

실제로 ... 블록 복사 및 붙여 넣기를 사용하여 올바르게 수행하는 방법이 있습니까? 이것은 결국 가장 쉬운 방법입니다 (특히 어떤 이유로 여기에서 더 복잡한 방법을 찾을 수없는 경우).
ThiefMaster

2
@Izkata와 같이 긴 줄 사이에 텍스트가 삽입되는 문제가 발생한다고 말합니다. 이 문제를 해결하려면 첫 줄 끝에 공백을 추가하여 가장 길게 만든 다음 텍스트 블록을 붙여 넣으십시오. 이 작업이 완료되면 여러 공간을 하나로 압축하는 것만 큼 간단합니다.:%s/ \+/ /g
Khaja Minhajuddin

1
set ve=all도움이 필요하면 vimdoc.sourceforge.net/htmldoc/options.html#'virtualedit '를 참조하십시오
Ben

19

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

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)

1
입력 [Enter]한 후 :5두 번 눌러야 합니다. 그렇지 않으면 작동하지 않습니다.
Shawn J. Goff

1
나는 gvim에있다. GVim에서 해당 명령을 복사하여 붙여 넣을 수있는 방법이 있습니까? ^ V는 현재 일반 (?) 모드에 있더라도 삽입 모드 (사람들이 일반적으로 원하는 것)에 자동으로 붙여 넣습니다. 나는 시도 :norm qama:5<CR>y$'a$p:5<CR>dd'ajq3@a했지만 실행 만 보인다 q.
ThiefMaster

1
ThiefMaster : 시도 :let @a="ma:5^My$'a$p:5^Mdd'aj" | normal 4@a1, ^M문자는 CTRL-V는 다음 Enter 키를 쳐서 입력된다.
rampion

8

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

:!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.

블록 선택을 사용하는 것이 유일한 방법은 아닙니다. 가장 간단한 것도 아닙니다. 원하는 ( paste -d유사한) 동작은 내 대답에 표시된 것처럼 짧은 Vim 명령을 사용하여 구현할 수 있습니다 .
ib.

3
그 외에도 Windows에있어 솔루션에 Linux 시스템에 대한 SSH 연결을 열고 편집기에서 터미널로 붙여 넣을 수 있습니다.
ThiefMaster

3

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

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

3

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

abc    123
def    45
...    ...

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

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

질문은 실제로 공백을 요구하지 않습니다. 나는 다음과 같이 할 것입니다 gvV:'<,'>s/\s+//g(vim은 자동으로 대신 삽입 '<,'>해야하므로 수동으로 입력 할 필요가 없습니다).
Ben

2

복잡한 반복을 사용합니다 :)

이것을 감안할 때 :

aaa
bbb
ccc

AAA
BBB
CCC

첫 번째 줄에 커서를두고 다음을 누르십시오.

qa}jdd''pkJxjq

그런 다음 @a (그리고 나중에 사용할 수 있습니다@@ 필요한만큼 ).

당신은 결국

aaaAAA
bbbBBB
cccCCC

(그리고 줄 바꿈.)

설명 :

  • qa 복잡한 반복 기록을 시작합니다 a

  • } 다음 빈 줄로 점프

  • jdd 다음 줄을 삭제

  • '' 마지막 점프 전의 위치로 돌아갑니다

  • p 삭제 된 줄을 현재 줄 아래에 붙여 넣기

  • kJ 현재 줄을 이전 줄 끝에 추가

  • xJ결합 된 줄 사이에 추가 되는 공간을 삭제하십시오 . 당신이 공간을 원한다면 이것을 생략 할 수 있습니다

  • j 다음 줄로 이동

  • q 복잡한 반복 기록을 종료

그 후 당신이 사용하는 거라고 @a에 저장되어있는 복잡한 반복을 실행 a한 다음 사용할 수 있습니다 @@마지막으로 실행 된 복잡한 반복을 다시 실행.


1

이를 달성하는 방법에는 여러 가지가 있습니다. 다음 두 가지 방법 중 하나를 사용하여 두 개의 텍스트 블록을 병합합니다.

첫 번째 블록이 라인 1에 있고 두 번째 블록이 라인 10에서 커서의 초기 위치로 라인 10에서 시작한다고 가정합니다.

(\ n은 Enter 키를 누르는 것을 의미합니다.)

1. abc
   def
   ghi        

10. 123
    456
    789

매크로를 사용하여 복사, 붙여 넣기 및 조인 명령을 사용하십시오.

qaqqa : + 9y \ npkJjq2 @ a10G3dd

명령을 사용하여 매크로를 사용하면 n 번째 줄 번호에서 한 줄을 이동하고 결합합니다.

qcqqc : 10 분. \ nkJjq2 @ c

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.