Fusionner plusieurs lignes (deux blocs) dans Vim

Je voudrais fusionner deux blocs de lignes dans Vim, c’est-à-dire prendre les lignes n..m et les append aux lignes a..b . Si vous préférez une explication de 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 le faire 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 juste des commandes Ex

 :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 ~ 

MISE À JOUR: Une réponse à ces nombreuses citations mérite une explication plus approfondie.

Dans Vim, vous pouvez utiliser le caractère pipe ( | ) pour enchaîner plusieurs commandes Ex, ce qui é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 sur lesquelles les commandes opèrent.

del supprime les lignes données. Il peut prendre un argument de registre, mais quand on ne le donne pas, il vide les lignes dans le registre sans nom, @" , comme le fait la suppression en mode normal. let l=split(@") puis divise les lignes supprimées , en utilisant le délimiteur par défaut: blanc. Pour travailler 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 séparateur 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 lisons. Nous pourrions remplacer les lignes supprimées dans l’ordre inverse en utilisant remove(l,-1) .

Une commande élégante et concise de résolution des problèmes 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 la réponse que j’ai donnée à la question ” Vim paste -d” comportement hors de la boîte? “.

Pour joindre des blocs de ligne, vous devez suivre les étapes suivantes:

  1. Aller à la troisième ligne: jj
  2. Entrer en mode bloc visuel: CTRL-v
  3. Ancrer le curseur à la fin de la ligne (important pour les lignes de différentes longueurs): $
  4. Aller à la fin: CTRL-END
  5. Couper le bloc: x
  6. Aller à la fin de la première ligne: kk$
  7. Collez le bloc ici: p

Le mouvement n’est pas le meilleur (je ne suis pas un expert), mais cela fonctionne comme vous le souhaitiez. J’espère qu’il y aura une version plus courte de celui-ci.

Voici les prérequirejs 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 les deux) XOR
  • La première ligne du bloc de départ n’est pas la plus longue et vous avez des espaces supplémentaires à la fin.

Voici comment je le ferais (avec le curseur sur la première ligne):

 qama:5y$'a$p:5dd'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).

Voici ce qui se passe:

  • qa enregistre tout jusqu’au q suivant dans un “tampon” dans a .
  • ma crée une marque sur la ligne en cours.
  • :5 va au groupe suivant.
  • y$ tire le rest de la ligne.
  • 'a retour à la marque, défini plus tôt.
  • $p à la fin de la ligne.
  • :5 revient à la première ligne du deuxième groupe.
  • dd supprime.
  • 'a retour à 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 également 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 de collage 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 de l’échantillon sont les mêmes que celles des rampions.

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

Je ne pense pas que ce soit trop compliqué. Je voudrais juste mettre virtualedit sur
( :set virtualedit=all )
Sélectionnez le bloc 123 et tous les suivants.
Mettez-le après la première colonne:

 abc 123 def 45 ... ... 

et supprimez l’espace multiple entre 1 espace:

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

J’utiliserais 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 le bouton suivant:

 qq}jdd''$pkJj0q 

puis appuyez sur @q (et vous pourrez ensuite utiliser @@ ) autant de fois que nécessaire.

Vous devriez vous retrouver avec:

 aaaAAA bbbBBB cccCCC 

(Plus une nouvelle ligne.)

Il peut y avoir de nombreuses façons d’y parvenir. Je vais fusionner deux blocs de texte en utilisant l’une des deux méthodes suivantes.

supposons que le premier bloc se trouve à la ligne 1 et que le deuxième bloc commence à la ligne 10 avec la position initiale du curseur au numéro de 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 joindre.

qaqqa: + 9y \ npkJjq2 @ a10G3dd

avec une macro utilisant les commandes, déplacez une ligne au nième numéro de ligne et rejoignez-la.

qcqqc: 10m. \ nkJjq2 @ c