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?

321
vim
demandé sur ThiefMaster 0000-00-00 00:00:00

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

876
répondu rampion 2013-06-10 17:13:48

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? ".

55
répondu ib. 2017-05-23 11:54:21

pour joindre les blocs de ligne, vous devez faire les étapes suivantes:

  1. allez à la troisième ligne: jj
  2. entrer en mode bloc visuel: CTRL-v
  3. ancrer le curseur à l'extrémité de la ligne (important pour les lignes de longueur différente): $
  4. à la fin: CTRL-END
  5. couper le bloc: x
  6. fin de la première ligne: kk$
  7. 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 et def ) 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.
44
répondu mliebelt 2012-06-01 15:48:51

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 prochain q dans un "buffer" dans a .
  • 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)
19
répondu Kenneth Ballenegger 2012-05-26 08:20:08

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.
8
répondu kevinlawler 2012-05-26 04:18:02

les données D'échantillon sont les mêmes que celles de rampion.

:1,4s/$/\=getline(line('.')+4)/ | 5,8d
3
répondu kev 2012-08-08 07:46:42

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
3
répondu Reman 2013-06-07 09:01:53

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

2
répondu Gerardo Marset 2012-07-14 15:39:10

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

1
répondu