Je voudrais fusionner deux blocs de lignes dans Vim, c'est-à-dire prendre des lignes n..m
et les ajouter à des 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
...
devrait devenir
abc123
def45
Existe-t-il un bon moyen de le faire sans faire de copier-coller manuellement?
x
avec joinx+2
?[a[i] + b[i] for i in min(len(a), len(b))]
Réponses:
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 le faire avec seulement des commandes Ex
va transformer
dans
MISE À JOUR: Une réponse avec autant de votes positifs mérite une explication plus approfondie.
Dans Vim, vous pouvez utiliser le caractère pipe (
|
) pour chaîner plusieurs commandes Ex, donc ce qui précède est équivalent àDe nombreuses commandes Ex acceptent une plage de lignes comme argument de préfixe - dans le cas ci-dessus,
5,8
avantdel
et1,4
avant les///
spécifient sur quelles lignes les commandes opèrent.del
supprime les lignes données. Il peut prendre un argument de registre, mais quand il n'est pas donné, il vide les lignes dans le registre sans nom@"
, tout comme 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: les espaces. Pour fonctionner correctement sur une entrée qui avait un espace dans les lignes supprimées, comme:nous avions besoin de spécifier un séparateur différent, pour éviter « le travail est » d'être divisé en deux éléments de la 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'expressionremove(l,0)
.remove(l,0)
modifie la listel
, 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 utilisantremove(l,-1)
.la source
s/\s*$/
au lieu des/$/
.:sil5,8del | let l=split(@") | sil1,4s/$/\=remove(l,0)/ | call histdel("/", -1) | nohls
semble être encore mieux car il nettoie l'historique de recherche après l'exécution. Et il n'affiche pas le message "x plus / moins de lignes" m'obligeant à appuyer sur Entrée.:help range
,:help :d
,:help :let
,:help split()
,:help :s
,:help :s\=
,:help remove()
.Une commande élégante et concise Ex résoudre le problème peut être obtenue en combinant les
:global
,:move
et les:join
commandes. 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.Pour une explication détaillée de cette technique, voir ma réponse à une question similaire Comportement de « Vim paste -d» hors de la boîte? ».
la source
E16: Invalid Range
- mais ça marche quand même. Lors de la suppression,1,
cela fonctionne sans l'erreur.:move
et:join!
, ni ce que''
signifiait comme argument de plage (:help ''
) et ce+
que-
signifiait comme modificateurs de plage (:help range
). Merci!sil!
à la commande.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 vouliez. J'espère qu'il y en aura une version plus courte.
Voici les prérequis pour que cette technique fonctionne bien:
abc
etdef
) ont la même longueur XORla source
abc
etdef
sont de la même longueur. La sélection de bloc conservera les retraits du texte supprimé, donc si le curseur est sur une ligne courte lors de la mise en place du texte, les lignes sont insérées entre les lettres sur les plus longues - et des espaces ajoutés aux plus courtes si le curseur était sur une plus longue une.:%s/ \+/ /g
set ve=all
devrait aider, voir vimdoc.sourceforge.net/htmldoc/options.html#'virtualedit 'Voici comment je le ferais (avec le curseur sur la première ligne):
Vous devez savoir deux choses:
Voici ce qui se passe:
qa
enregistre tout jusqu'au prochainq
dans un "tampon" dansa
.ma
crée une marque sur la ligne actuelle.:5<CR>
va au groupe suivant.y$
tire le reste de la ligne.'a
revient à la marque définie plus tôt.$p
pâtes en fin de ligne.:5<CR>
revient à la première ligne du deuxième groupe.dd
le supprime.'a
revient à 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)la source
[Enter]
après les:5
deux saisies ou cela ne fonctionnera pas.:norm qama:5<CR>y$'a$p:5<CR>dd'ajq3@a
mais cela semble s'exécuter seulementq
.:let @a="ma:5^My$'a$p:5^Mdd'aj" | normal 4@a
, où les^M
caractères sont saisis en appuyant sur CTRL-V puis sur Entrée.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'
paste
utilitaire a été créé pour gérer ce type de fusion de lignes.la source
paste -d
comportement souhaité ( -like) peut être mis en œuvre au moyen de la commande Vim courte, comme indiqué dans ma réponse .Les exemples de données sont les mêmes que ceux de rampion.
la source
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 ci-dessous.
Mettez-le après la première colonne:
et supprimez l'espace multiple entre 1 espace:
la source
gvV:'<,'>s/\s+//g
(vim devrait automatiquement insérer le'<,'>
pour vous afin que vous n'ayez pas besoin de le taper manuellement).J'utiliserais des répétitions complexes :)
Compte tenu de ceci:
Avec le curseur sur la première ligne, appuyez sur ce qui suit:
puis appuyez sur
@a
(et vous pouvez ensuite utiliser@@
) autant de fois que nécessaire.Vous devriez vous retrouver avec:
(Plus une nouvelle ligne.)
Explication:
qa
commence à enregistrer une répétition complexe dansa
}
saute à la prochaine ligne videjdd
supprime la ligne suivante''
revient à la position avant le dernier sautp
collez la ligne supprimée sous la ligne actuellekJ
ajouter la ligne actuelle à la fin de la précédentex
supprimer l'espace quiJ
s'ajoute entre les lignes combinées; vous pouvez omettre cela si vous voulez de l'espacej
aller à la ligne suivanteq
terminer l'enregistrement répétitif complexeAprès cela, vous utiliseriez
@a
pour exécuter la répétition complexe stockée dansa
, puis vous pouvez utiliser@@
pour réexécuter la dernière répétition complexe exécutée.la source
Il peut y avoir de nombreuses façons d'y parvenir. Je fusionnerai 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 à la ligne numéro 1.
(\ n signifie appuyer sur la touche Entrée.)
avec une macro en utilisant les commandes: copier, coller et joindre.
avec une macro en utilisant les commandes déplacer une ligne au nième numéro de ligne et rejoindre.
la source