J'aimerais fusionner deux blocs de lignes dans Vim, c'est-à-dire prendre les lignes n..m
et les ajouter aux lignes a..b
. Si vous préférez une explication pseudocode: [a[i] + b[i] for i in min(len(a), len(b))]
Exemple:
abc
def
...
123
45
...
devraient devenir
abc123
def45
Existe-t-il un bon moyen de faire cela sans copier/coller manuellement?
Vous pouvez certainement faire tout cela avec un seul copier/coller (en utilisant la sélection en mode bloc), mais je suppose que ce n'est pas ce que vous voulez.
Si vous voulez faire cela avec seulement Ex commandes
:5,8del | let l=split(@") | 1,4s/$/\=remove(l,0)/
va transformer
work it
make it
do it
makes us
harder
better
faster
stronger
~
dans
work it harder
make it better
do it faster
makes us stronger
~
UPDATE: Une réponse avec autant de votes positifs mérite une explication plus approfondie.
Dans Vim, vous pouvez utiliser le caractère de pipe (|
) pour chaîner plusieurs commandes Ex, ainsi ce qui précède équivaut à
:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/
De nombreuses commandes Ex acceptent une plage de lignes comme argument de préfixe - dans le cas ci-dessus, le 5,8
avant le del
et le 1,4
avant le s///
spécifient les lignes utilisées par les commandes. sur.
del
supprime les lignes données. Cela peut prendre un argument de registre, mais quand aucun n'est spécifié, il vide les lignes dans le registre sans nom, @"
, comme le fait la suppression en mode normal. let l=split(@")
divise ensuite les lignes supprimées en une liste, en utilisant le délimiteur par défaut: espace. Pour fonctionner correctement sur une entrée comportant des espaces dans les lignes supprimées, comme:
more than
hour
our
never
ever
after
work is
over
~
nous aurions besoin de spécifier un délimiteur différent, pour éviter que "work is" ne soit divisé en deux éléments de liste: let l=split(@","\n")
.
Enfin, dans la substitution s/$/\=remove(l,0)/
, nous remplaçons la fin de chaque ligne ($
) par la valeur de l'expression remove(l,0)
. remove(l,0)
modifie la liste l
, en supprimant et en renvoyant son premier élément. Cela nous permet de remplacer les lignes supprimées dans l'ordre dans lequel nous les avons lues. Nous pourrions remplacer les lignes supprimées dans l'ordre inverse en utilisant remove(l,-1)
.
Une commande Ex élégante et concise permettant de résoudre le problème peut être obtenue en combinant les commandes :global
, :move
et :join
. En supposant que le premier bloc de lignes commence sur la première ligne du tampon et que le curseur se trouve sur la ligne précédant immédiatement la première ligne du deuxième bloc, la commande est la suivante.
:1,g/^/''+m.|-j!
Pour une explication détaillée de la technique utilisée, voir le réponse J'ai donné à la question " le comportement de Vim-d '' sorti de la boîte? ".
Pour joindre des blocs de ligne, vous devez suivre les étapes suivantes:
jj
CTRL-v
$
CTRL-END
x
kk$
p
Le mouvement n'est pas le meilleur (je ne suis pas un expert), mais il fonctionne comme vous le souhaitiez. J'espère qu'il y en aura une version plus courte.
Voici les prérequis pour que cette technique fonctionne bien:
abc
et def
) ont la même longueur XORVoici comment je le ferais (avec le curseur sur la première ligne):
qama:5<CR>y$'a$p:5<CR>dd'ajq3@a
Vous devez savoir deux choses:
Voici ce qui se passe:
qa
enregistre tout jusqu'au q
suivant dans un "tampon" dans a
.ma
crée un repère sur la ligne en cours.:5<CR>
passe au groupe suivant.y$
tire le reste de la ligne.'a
retourne à la marque définie précédemment.$p
colle en fin de ligne.:5<CR>
retourne à la première ligne du deuxième groupe.dd
le supprime.'a
retourne à la marque.jq
descend d'une ligne et arrête l'enregistrement.3@a
répète l'action pour chaque ligne (3 dans mon cas)Comme mentionné ailleurs, la sélection de blocs est la voie à suivre. Mais vous pouvez aussi utiliser n’importe quelle variante de:
:!tail -n -6 % | paste -d '\0' % - | head -n 5
Cette méthode repose sur la ligne de commande UNIX. L'utilitaire paste
a été créé pour gérer ce type de fusion de lignes.
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.
Les exemples de données sont les mêmes que ceux de Rampion.
:1,4s/$/\=getline(line('.')+4)/ | 5,8d
Je ne pense pas que cela soit trop compliqué. Je voudrais juste mettre virtualedit sur
(:set virtualedit=all
)
Sélectionnez le bloc 123 et tous ci-dessous.
Mettez-le après la première colonne:
abc 123
def 45
... ...
et supprimez les espaces multiples entre 1 espace:
:%s/\s\{2,}/ /g
Je voudrais utiliser des répétitions complexes :)
Compte tenu de ceci:
aaa
bbb
ccc
AAA
BBB
CCC
Avec le curseur sur le premier "a" de la première ligne, appuyez sur ce qui suit:
qq}jdd''$pkJj0q
puis appuyez sur @q
(vous pourrez ensuite utiliser @@
) autant de fois que nécessaire.
Vous devriez vous retrouver avec:
aaaAAA
bbbBBB
cccCCC
(Plus une nouvelle ligne.)
Il y a beaucoup de façons d'accomplir cela. Je vais fusionner deux blocs de texte en utilisant l'une des deux méthodes suivantes.
supposons que le premier bloc est à la ligne 1 et que le deuxième bloc commence à la ligne 10, la position initiale du curseur étant à la ligne 1.
(\ n signifie appuyer sur la touche Entrée.)
1. abc
def
ghi
10. 123
456
789
avec une macro en utilisant les commandes: copier, coller et rejoindre.
qaqqa: + 9y\npkJjq2 @ a10G3dd
avec une macro en utilisant les commandes déplacer une ligne au numéro de ligne nième et rejoindre.
qcqqc: 10m.\nkJjq2 @ c