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

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

Пример:

abc
def
...

123
45
...

должен стать

abc123
def45

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

Ответ 1

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

Если вы хотите сделать это с помощью 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 вы можете использовать символ pipe (|) для объединения нескольких команд Ex, поэтому приведенное выше эквивалентно

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

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

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

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).

Ответ 2

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

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

Подробное объяснение используемой техники см. в ответе , который я дал вопрос " "Vim paste -d" " поведение из коробки?".

Ответ 3

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

  • Перейдите к третьей строке: jj
  • Введите режим визуального блока: CTRL-v
  • привязать курсор к концу строки (важно для строк различной длины): $
  • Перейти к концу: CTRL-END
  • Вырезать блок: x
  • Перейти в конец первой строки: kk$
  • Вставьте блок здесь: p

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

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

  • Все строки стартового блока (в примере в вопросе abc и def) имеют одинаковую длину XOR
  • первая строка стартового блока самая длинная, и вам не нужны дополнительные промежутки между ними) XOR
  • Первая строка стартового блока не самая длинная, а дополнительные пробелы до конца.

Ответ 4

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

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

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

  • Номер строки, на которой начинается первая строка второй группы (5 в моем случае), и
  • количество строк в каждой группе (3 в моем примере).

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

  • qa записывает все до следующего q в "буфер" в a.
  • ma создает метку в текущей строке.
  • :5<CR> переходит к следующей группе.
  • y$ удаляет остальную часть строки.
  • 'a возвращается к знаку, установленному ранее.
  • $p пасты в конце строки.
  • :5<CR> возвращается во вторую строку первой группы.
  • dd удаляет его.
  • 'a возвращается к отметке.
  • jq переходит на одну строку и останавливает запись.
  • [email protected] повторяет действие для каждой строки (3 в моем случае)

Ответ 5

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

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

Ответ 6

Пример данных такой же, как и у рампы.

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

Ответ 7

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

abc    123
def    45
...    ...

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

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

Ответ 8

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

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

aaa
bbb
ccc

AAA
BBB
CCC

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

qq}jdd''$pkJj0q

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

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

aaaAAA
bbbBBB
cccCCC

(плюс новая строка.)

Ответ 9

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

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

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

1. abc
   def
   ghi        

10. 123
    456
    789

с помощью макроса с помощью команд: copy, paste и join.

qaqqa: + 9y\npkJjq2 @a10G3dd

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

qcqqc: 10m.\nkJjq2 @c