Объединение нескольких строк (два блока) в 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