Объединить несколько строк (два блока) в Vim

Я хотел бы объединить два блока строк в Vim, то есть взять строкиn..m и добавить их в строкиa..b, Если вы предпочитаете объяснение псевдокода:[a[i] + b[i] for i in min(len(a), len(b))]

Пример:

abc
def
...

123
45
...

должен стать

abc123
def45

Есть ли хороший способ сделать это без ручного копирования и вставки?

Ответы на вопрос(9)

Элегантная и лаконичная команда Ex, решающая проблему, может быть получена объединяя:global, :move, а также:join команды. Предполагая, что первый блок строк начинается с первой строки буфера, и что курсор находится на линии, непосредственно предшествующей первой строке Второй блок, команда выглядит следующим образом.

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

Для подробного объяснения используемой техники, см.ответ Я дал вопрос & quot;Vim paste -d & apos; & APOS; поведение из коробки?& Quot ;.

Есть много способов сделать это. Я объединю два блока текста, используя любой из следующих двух методов.

предположим, что первый блок находится в строке 1, а второй блок начинается со строки 10 с начальной позиции курсора в строке номер 1.

(\ n означает нажатие клавиши ввода.)

1. abc
   def
   ghi        

10. 123
    456
    789

с макросом, используя команды: копировать, вставить и присоединиться.

qaqqa:+9y\[email protected]

с помощью макроса с помощью команд переместите строку на номер n-й строки и присоединитесь.

qcqqc:10m .\[email protected]

Решение Вопроса

Конечно, вы можете сделать все это с помощью одной копии / вставки (с использованием выбора в блочном режиме), но я предполагаю, что это не то, что вам нужно.

Если вы хотите сделать это простобывший команды

: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
~

UPDATE: Ответ с таким большим количеством голосов заслуживает более подробного объяснения.

В Vim вы можете использовать символ трубы (|) для объединения нескольких команд Ex, поэтому приведенное выше эквивалентно

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

Многие команды Ex принимают диапазон строк в качестве аргумента префикса - в приведенном выше случае5,8 передdel и1,4 передs/// укажите, над какими строками работают команды.

del удаляет указанные строки. Он может принимать аргумент регистра, но когда он не задан, он сбрасывает строки в безымянный регистр,@"так же, как удаление в обычном режиме.let l=split(@") затем разбивает удаленные строки в список, используя разделитель по умолчанию: пробел. Для правильной работы с вводом, который имеет пробелы в удаленных строках, например:

more than 
hour 
our 
never 
ever
after
work is
over
~

нам нужно указать другой разделитель, чтобы "работа не была" от разделения на два элемента списка:let l=split(@","\n").

Наконец, в заменs/$/\=remove(l,0)/заменяем конец каждой строки ($) со значением выраженияremove(l,0). remove(l,0) меняет списокl, удалив и вернув первый элемент. Это позволяет нам заменять удаленные строки в том порядке, в котором мы их читаем. Вместо этого мы могли бы заменить удаленные строки в обратном порядке, используяremove(l,-1).

Я бы не стал делать это слишком сложным. Я бы просто поставил virtualedit на
(:set virtualedit=all)
Выберите блок 123 и все ниже.
Поместите это после первого столбца:

abc    123
def    45
...    ...

и удалите несколько пробелов между 1 пробелом:

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

Данные выборки такие же, как у Rampion.

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

Я бы использовал сложные повторы :)

Учитывая это:

aaa
bbb
ccc

AAA
BBB
CCC

С курсором на первом «а» в первой строке нажмите следующее:

qq}jdd''$pkJj0q

а затем нажмите@q (и вы можете впоследствии использовать@@) столько раз, сколько нужно.

Вы должны в конечном итоге:

aaaAAA
bbbBBB
cccCCC

(Плюс перевод строки)

Чтобы соединить блоки строки, вы должны сделать следующие шаги:

  1. Go to the third line: jj
  2. Enter visual block mode: CTRL-v
  3. Anchor the cursor to the end of the line (important for lines of differing length): $
  4. Go to the end: CTRL-END
  5. Cut the block: x
  6. Go to the end of the first line: kk$
  7. Paste the block here,: p

Движение не самое лучшее (я не эксперт), но оно работает так, как вы хотели. Надеюсь, что будет более короткая версия.

Вот предварительные условия, чтобы этот метод работал хорошо:

  • All lines of the starting block (in the example in the question abc and def) have the same length XOR
  • the first line of the starting block is the longest, and you don't care about the additional spaces in between) XOR
  • The first line of the starting block is not the longest, and you additional spaces to the end.

Вот как я это сделаю (с курсором на первой строке):

qama:5<CR>y
qama:5<CR>y$'a$p:5<CR>dd'[email protected]
apos;a$p:5<CR>dd'[email protected]

Вам нужно знать две вещи:

  • The line number on which the first line of the second group starts (5 in my case), and
  • the number of lines in each group (3 in my example).

Вот что происходит:

  • qa records everything up to the next q into a "buffer" in a.
  • ma creates a mark on the current line.
  • :5<CR> goes to the next group.
  • y$ yanks the rest of the line.
  • 'a returns to the mark, set earlier.
  • $p pastes at the end of the line.
  • :5<CR> returns to the second group's first line.
  • dd deletes it.
  • 'a returns to the mark.
  • jq goes down one line, and stops recording.
  • [email protected] repeats the action for each line (3 in my case)

Как упоминалось в другом месте, выбор блока - это путь. Но вы также можете использовать любой вариант:

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

Ваш ответ на вопрос