Je pense que la commande suivante devrait fonctionner:
:%s/^\(.*\)\(\n\1\)\+$/\1/
Explication:
Nous utilisons la commande de substitution sur l'ensemble du fichier pour changer pattern
en string
:
:%s/pattern/string/
Ici pattern
est ^\(.*\)\(\n\1\)\+$
et string
est \1
.
pattern
peut être décomposé comme ceci:
^\(subpattern1\)\(subpattern2\)\+$
^
et $
correspondent respectivement à un début de ligne et à une fin de ligne.
\(
et \)
sont utilisés pour joindre subpattern1
afin que nous puissions y faire référence plus tard par le numéro spécial \1
.
Ils sont également utilisés pour entourer subpattern2
afin que nous puissions le répéter 1 ou plusieurs fois avec le quantificateur \+
.
subpattern1
is .*
.
est un métacaractère correspondant à n'importe quel caractère sauf la nouvelle ligne et *
est un quantificateur qui correspond au dernier caractère 0, 1 ou plusieurs fois.
Correspond donc à .*
tout texte ne contenant pas de nouvelle ligne.
subpattern2
is \n\1
\n
correspond à une nouvelle ligne et \1
correspond au même texte qui a été trouvé à l'intérieur de la première \(
, \)
qui est ici subpattern1
.
On pattern
peut donc le lire ainsi:
un début de ligne ( ^
) suivi de tout texte ne contenant pas de nouvelle ligne ( .*
) suivi d'une nouvelle ligne ( \n
) puis du même texte ( \1
), les deux derniers étant répétés une ou plusieurs fois ( \+
), et enfin une fin de ligne ( $
) .
Partout où pattern
est mis en correspondance (un bloc de lignes identiques), la commande de substitution le remplace par string
lequel se trouve ici \1
(la première ligne du bloc).
Si vous souhaitez voir quels blocs de lignes seront affectés sans rien changer dans votre fichier, vous pouvez activer l' hlsearch
option et ajouter l' n
indicateur de substitution à la fin de la commande:
:%s/^\(.*\)\(\n\1\)\+$/\1/n
Pour un contrôle plus précis, vous pouvez également demander une confirmation avant de modifier chaque bloc de lignes en ajoutant à la c
place l'indicateur de substitution:
:%s/^\(.*\)\(\n\1\)\+$/\1/c
Pour plus d'informations sur la commande de substitution lue :help :s
,
pour les indicateurs de substitution :help s_flags
,
pour les différents métacaractères et quantificateurs lus :help pattern-atoms
,
et pour les expressions régulières dans vim, lisez ceci .
Edit: Wildcard a corrigé un problème dans la commande en ajoutant un $
à la fin de pattern
.
Aussi BloodGain a une version plus courte et plus lisible de la même commande.
$
. Sinon, il fera des choses inattendues avec une ligne qui commence par un texte identique à la ligne précédente, mais qui a d'autres caractères de fin. Notez également que la commande de base que vous avez donnée est fonctionnellement équivalente à ma réponse:%!uniq
, mais les indicateurs de surbrillance et de confirmation sont agréables.\n
correspond à une fin de ligne et devrait empêcher cela, mais ce n'est pas le cas. J'ai essayé d'ajouter un$
peu après.*
sans succès. Je vais essayer de le réparer, mais si je ne peux pas, je vais peut-être supprimer ma réponse ou ajouter un avertissement à la fin. Merci d'avoir signalé ce problème.:%s/^\(.*\)\(\n\1\)\+$/\1/
$
correspond à la fin de la chaîne et non à la fin de la ligne. Ce n'est techniquement pas vrai, mais lorsque vous ajoutez des caractères après quelques exceptions, cela correspond à un littéral$
au lieu de quelque chose de spécial. Il\n
est donc préférable d' utiliser pour les correspondances sur plusieurs lignes. (Voir:help /$
)\n
peut être utilisé n'importe où à l'intérieur de l'expression régulière alors qu'il$
ne devrait probablement être utilisé qu'à la fin. Juste pour faire une différence entre les deux, j'ai édité la réponse en écrivant qui\n
correspond à une nouvelle ligne (ce qui vous fait instinctivement penser qu'il y a encore du texte après) alors que$
correspond à une fin de ligne (ce qui vous fait penser qu'il n'y a rien la gauche).Essayez ce qui suit:
Comme pour la réponse de saginaw , cela utilise la commande Vim: substitute. Cependant, il profite de quelques fonctionnalités supplémentaires pour améliorer la lisibilité:
\v
signifie «très magique» ou tous les caractères sauf alphanumérique ( A-z0-9 ) et trait de soulignement ( _ ) ont une signification particulière.La signification des composants est:
la source
\n
et$
.\n
ajoute quelque chose au motif: la nouvelle ligne de caractère qui indique à vim que le texte suivant est sur une nouvelle ligne. Alors$
que n'ajoute rien au motif, il interdit simplement une correspondance si le caractère suivant en dehors du motif n'est pas une nouvelle ligne. C'est du moins ce que j'ai compris en lisant votre réponse et:help zero-width
.^
, cela n'ajoute rien au motif, cela empêche juste qu'une correspondance soit faite si le caractère précédent en dehors du motif n'est pas une nouvelle ligne ...+
signifie «répéter l'expression précédente (caractère ou groupe) 1 fois ou plus», mais ne correspond à rien lui-même. Le^
moyen «ne peut pas commencer au milieu de la chaîne» et$
signifie «ne peut pas se terminer au milieu de la chaîne». Remarquez que je n'ai pas dit «ligne», mais «chaîne». Vim traite chaque ligne comme une chaîne par défaut - et c'est là\n
qu'intervient. Il dit à Vim de consommer une nouvelle ligne pour essayer de faire cette correspondance.Si vous souhaitez supprimer TOUTES les lignes identiques adjacentes, et pas seulement
Hold
, vous pouvez le faire extrêmement facilement avec un filtre externe de l'intérieurvim
::%!uniq
(dans un environnement Unix).Si vous voulez le faire directement
vim
, c'est en fait très délicat. Je pense qu'il y a un moyen, mais pour le cas général, il est très difficile de le rendre 100% fonctionnel et je n'ai pas encore résolu tous les bugs.Cependant, pour ce cas spécifique , puisque vous pouvez voir visuellement que la ligne suivante qui n'est pas en double ne commence pas par le même caractère, vous pouvez utiliser:
La
+
signifie la ligne après la ligne actuelle. Le . fait référence à la ligne actuelle. La/^[^H]/-
signifie la ligne avant (-
) la ligne suivante qui ne commence pas par H.Ensuite, d est supprimé.
la source
uniq
(à partir de l'intérieur de vim ou à l'aide du shell) est la façon dont je résoudrais cela. D'une part, je suis sûruniq
que les lignes vides / tous les espaces seront équivalents (je ne l'ai pas testé), mais ce serait beaucoup plus difficile à capturer avec une expression régulière. Cela signifie également de ne pas «réinventer la roue» pendant que j'essaie de faire le travail.Une réponse basée sur Vim:
= Remplacez chaque ligne suivie par elle-même au moins une fois , par cette même ligne.
la source
Un de plus, en supposant que Vim 7.4.218 ou version ultérieure:
Ce n'est pas nécessairement meilleur que les autres solutions.
la source
Voici une solution basée sur un vieux (2003) vim (golf) de Preben Gulberg et Piet Delport.
%g/^\v(.*)\n\1$/d
:Uniq
(équivalent à:%Uniq
),:1,Uniq
(du début du buffer à la ligne courante),:Uniq<cr>
(développé par vim en:'<,'>Uniq
):h range
)Voici le code:
Remarque: leurs premières tentatives ont été:
la source