Fusionner plusieurs lignes (deux blocs) dans Vim
je voudrais fusionner deux blocs de lignes dans Vim, i.e. prendre les lignes n..m
et les ajouter aux lignes a..b
. Si vous préférez un pseudo explication: [a[i] + b[i] for i in min(len(a), len(b))]
exemple:
abc
def
...
123
45
...
devrait devenir
abc123
def45
y a-t-il une bonne façon de faire cela sans copier&coller manuellement?
9 réponses
vous pouvez certainement faire tout cela avec un simple copier/coller (en utilisant la sélection de mode bloc), mais je devine que ce n'est pas ce que vous voulez.
si vous voulez le faire avec juste Ex commandes
:5,8del | let l=split(@") | 1,4s/$/\=remove(l,0)/
transformera
work it
make it
do it
makes us
harder
better
faster
stronger
~
en
work it harder
make it better
do it faster
makes us stronger
~
mise à jour: une réponse avec autant de notes positives mérite une explication plus approfondie.
dans Vim, vous pouvez utiliser le caractère pipe ( |
) pour enchaîner plusieurs commandes Ex, de sorte que ce qui précède est équivalent à
:5,8del
:let l=split(@")
:1,4s/$/\=remove(l,0)/
beaucoup de commandes Ex acceptent une gamme 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 sur quelles lignes les commandes opèrent.
del
supprime compte tenu de lignes. Il peut prendre un argument de registre, mais quand un n'est pas donné, il vide les lignes vers le registre sans nom, @"
, tout comme la suppression en mode normal le fait. let l=split(@")
divise ensuite les lignes supprimées en une liste, en utilisant le délimiteur par défaut: whitespace. Pour travailler correctement sur l'entrée qui avait 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 ( $
) avec 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 lisons. Nous pourrions remplacer les lignes supprimées dans l'ordre inverse en utilisant remove(l,-1)
.
une commande élégante et concise peut être obtenue en
combinant les commandes :global
, :move
et :join
. En supposant que le
le premier bloc de lignes Commence sur la première ligne du tampon, et que le
le curseur est situé sur la ligne précédant immédiatement la première ligne de la
deuxième bloc, la commande est la suivante.
:1,g/^/''+m.|-j!
pour une explication détaillée de la technique utilisée, voir la réponse I donné à la question " vim paste-d ' comportement de la boîte? ".
pour joindre les blocs de ligne, vous devez faire les étapes suivantes:
- allez à la troisième ligne:
jj
- entrer en mode bloc visuel:
CTRL-v
- ancrer le curseur à l'extrémité de la ligne (important pour les lignes de longueur différente):
$
- à la fin:
CTRL-END
- couper le bloc:
x
- fin de la première ligne:
kk$
- coller le bloc ici:
p
Le mouvement n'est pas le meilleur (je ne suis pas un expert), mais ça fonctionne comme tu le voulais. Espérons qu'il y aura une version plus courte.
Voici les conditions préalables pour que cette technique fonctionne bien:
- Toutes les lignes du bloc de départ (dans l'exemple de la question
abc
etdef
) ont la même longueur XOR - la première ligne du bloc de départ est la plus longue, et vous ne vous souciez pas des espaces supplémentaires entre) XOR
- La première ligne du bloc de départ n'est pas la plus longue, et des espaces à la fin.
Voici 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:
- le numéro de ligne sur lequel la première ligne du deuxième groupe commence (5 dans mon cas), et
- le nombre de lignes dans chaque groupe (3 dans mon exemple).
voilà ce qui se passe:
-
qa
enregistre tout jusqu'au prochainq
dans un "buffer" dansa
. -
ma
crée une marque sur la ligne actuelle. -
:5<CR>
va au groupe suivant. -
y$
renvoie le reste de la ligne. -
'a
renvoie à la marque, fixée antérieurement. -
$p
pâtes à la fin de la ligne. -
:5<CR>
retourne au deuxième groupe première ligne. -
dd
la supprime. -
'a
retourne à la marque. -
jq
descend une ligne et cesse d'enregistrer. -
3@a
répète l'action pour chaque ligne (3 dans mon cas)
comme nous l'avons mentionné ailleurs, la sélection des blocs est la voie à suivre. Mais vous pouvez également utiliser n'importe quelle variante de:
:!tail -n -6 % | paste -d '"151910920"' % - | 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 données D'échantillon sont les mêmes que celles de rampion.
:1,4s/$/\=getline(line('.')+4)/ | 5,8d
Je ne pense pas que ce soit trop compliqué.
Je mettrais juste virtualedit sur
( :set virtualedit=all
)
Sélectionnez le bloc 123 et tout ce qui suit.
Mettez-le après la première colonne:
abc 123
def 45
... ...
et supprimer l'espace multiple entre à 1 espace:
:%s/\s\{2,}/ /g
je voudrais utiliser complexes répète :)
étant donné que:
aaa
bbb
ccc
AAA
BBB
CCC
avec le curseur à la première ligne" a", appuyez sur le bouton Suivant:
qq}jdd''$pkJj0q
puis appuyez sur @q
(et vous pouvez ensuite utiliser @@
) autant de fois que nécessaire.
vous devriez finir avec:
aaaAAA
bbbBBB
cccCCC
(Plus une nouvelle ligne.)
il y a plusieurs façons d'y arriver. Je vais fusionner les deux blocs de texte utilisant une des deux méthodes suivantes.
supposons que le premier bloc soit à la ligne 1 et que le deuxième bloc commence à la ligne 10 avec la position initiale du curseur à la ligne 1.
(\n signifie appuyer sur la touche Entrée.)
1. abc
def
ghi
10. 123
456
789
avec une macro utilisant les commandes: Copier,Coller et joindre.
qaqqa:+9y\npkJjq2@a10g3dd