Ich denke, der folgende Befehl sollte funktionieren:
:%s/^\(.*\)\(\n\1\)\+$/\1/
Erklärung:
Wir verwenden die Substitution Befehl auf die gesamte Datei zu ändern pattern
in string
:
:%s/pattern/string/
Hier pattern
ist ^\(.*\)\(\n\1\)\+$
und string
ist \1
.
pattern
kann wie folgt aufgeteilt werden:
^\(subpattern1\)\(subpattern2\)\+$
^
und $
stimmen jeweils mit einem Zeilenanfang und einem Zeilenende überein.
\(
und \)
dienen zum Einschließen, subpattern1
damit wir später durch die spezielle Nummer darauf verweisen können \1
.
Sie werden auch zum Einschließen verwendet, subpattern2
damit wir sie mindestens einmal mit dem Quantor wiederholen können \+
.
subpattern1
ist .*
.
ein Metazeichen, das mit einem beliebigen Zeichen außer einer neuen Zeile übereinstimmt, und *
ein Quantifizierer, der mit dem letzten Zeichen 0, 1 oder mehrmals übereinstimmt .
Stimmt also .*
mit jedem Text überein, der keine neue Zeile enthält.
subpattern2
Es \n\1
\n
stimmt mit einer neuen Zeile \1
überein und stimmt mit dem gleichen Text überein, der in der ersten übereinstimmte. Dies \(
ist \)
hier subpattern1
.
Man pattern
kann also so lesen:
ein Zeilenanfang ( ^
) gefolgt von einem beliebigen Text, der keine neue Zeile ( .*
) enthält, gefolgt von einer neuen Zeile ( \n
) und demselben Text ( \1
), wobei die beiden letzteren ein oder mehrere Male wiederholt werden ( \+
) und endlich ein Zeilenende ( $
) .
Wo immer pattern
eine Übereinstimmung vorliegt (ein Block mit identischen Zeilen), ersetzt der Ersetzungsbefehl string
den hier angegebenen \1
(die erste Zeile des Blocks).
Wenn Sie sehen möchten, welche Zeilenblöcke betroffen sind, ohne etwas in Ihrer Datei zu ändern, können Sie die hlsearch
Option aktivieren und das n
Substitutionsflag am Ende des Befehls hinzufügen :
:%s/^\(.*\)\(\n\1\)\+$/\1/n
Für eine genauere Kontrolle können Sie auch eine Bestätigung anfordern, bevor Sie jeden Zeilenblock ändern, indem Sie c
stattdessen das Substitutionsflag hinzufügen :
:%s/^\(.*\)\(\n\1\)\+$/\1/c
Weitere Informationen über die Substitution Lesebefehl :help :s
,
für die Substitution Fahnen :help s_flags
,
für die verschiedenen Metazeichen und quantifiers lesen :help pattern-atoms
,
und für reguläre Ausdrücke in vim lesen diese .
Bearbeiten: Platzhalter behebt ein Problem im Befehl durch Hinzufügen eines $
am Ende von pattern
.
Auch BloodGain hat eine kürzere und besser lesbare Version des gleichen Befehls.
$
. Andernfalls werden unerwartete Aktionen mit einer Zeile ausgeführt, die mit dem gleichen Text wie die vorherige Zeile beginnt , jedoch andere nachgestellte Zeichen enthält. Beachten Sie auch, dass der grundlegende Befehl, den Sie gaben, meiner Antwort von funktional entspricht:%!uniq
, aber die Markierungs- und Bestätigungs-Flags sind nett.\n
stimmt mit einem Zeilenende überein und sollte dies verhindern, tut es aber nicht. Ich habe versucht, ein$
kurz nach.*
ohne Erfolg hinzuzufügen . Ich werde versuchen, das Problem zu beheben, aber wenn ich es nicht kann, werde ich möglicherweise meine Antwort löschen oder am Ende eine Warnung hinzufügen. Vielen Dank, dass Sie auf dieses Problem hingewiesen haben.:%s/^\(.*\)\(\n\1\)\+$/\1/
$
Ende der Zeichenfolge und nicht das Ende der Zeile übereinstimmt . Dies ist technisch gesehen nicht wahr - aber wenn Sie Zeichen bis auf wenige Ausnahmen nachstellen, entspricht dies einem Literal und$
nicht etwas Besonderem. Verwenden\n
ist also besser für mehrzeilige Matches. (Siehe:help /$
)\n
dass es überall innerhalb des regulären Ausdrucks verwendet werden kann, wohingegen$
es wahrscheinlich nur am Ende verwendet werden sollte. Um einen Unterschied zwischen den beiden zu machen, habe ich die Antwort so bearbeitet, dass sie\n
mit einer neuen Zeile übereinstimmt (was Sie instinktiv denken lässt, dass noch Text folgt), wohingegen$
ein Zeilenende übereinstimmt (was Sie glauben lässt, dass es nichts gibt) links).Versuche Folgendes:
Wie bei der Antwort von saginaw wird der Befehl: substitute von Vim verwendet. Es werden jedoch einige zusätzliche Funktionen zur Verbesserung der Lesbarkeit verwendet:
\v
"sehr magisch" oder alle Zeichen außer alphanumerisch ( A-z0-9 ) und Unterstrich ( _ ) haben eine besondere Bedeutung.Die Komponenten haben folgende Bedeutung:
quelle
\n
und besser verstehe$
.\n
fügt dem Muster etwas hinzu: das Zeichen new line, das vim mitteilt, dass sich der folgende Text in einer neuen Zeile befindet. Während$
dem Muster nichts hinzugefügt wird, wird lediglich eine Übereinstimmung ausgeschlossen, wenn das nächste Zeichen außerhalb des Musters keine neue Zeile ist. Zumindest habe ich das verstanden, als ich Ihre Antwort gelesen habe und:help zero-width
.^
, es fügt nichts zum Muster hinzu, es verhindert nur, dass eine Übereinstimmung hergestellt wird, wenn das vorherige Zeichen außerhalb des Musters keine neue Zeile ist ...+
"den vorhergehenden Ausdruck (Zeichen oder Gruppe) 1 oder mehrmals wiederholen", entspricht aber selbst nichts. Das^
Mittel "kann nicht in der Mitte der Zeichenfolge beginnen" und das$
Mittel "kann nicht in der Mitte der Zeichenfolge enden". Beachten Sie, dass ich dort nicht "line", sondern "string" gesagt habe. Vim behandelt jede Zeile standardmäßig als Zeichenfolge - und\n
genau hier kommt es an. Vim wird angewiesen, eine neue Zeile zu belegen, um zu versuchen, diese Übereinstimmung herzustellen.Wenn Sie ALLE benachbarten identischen Linien entfernen möchten
Hold
, können Sie dies äußerst einfach mit einem externen Filter von innen tunvim
::%!uniq
(In einer Unix-Umgebung).Wenn Sie es direkt in tun möchten
vim
, ist es tatsächlich sehr schwierig. Ich denke, es gibt einen Weg, aber für den allgemeinen Fall ist es sehr schwierig, ihn zu 100% funktionsfähig zu machen, und ich habe noch nicht alle Fehler behoben.In diesem speziellen Fall können Sie jedoch Folgendes verwenden, da Sie visuell sehen können, dass die nächste nicht duplizierte Zeile nicht mit demselben Zeichen beginnt:
Das
+
bedeutet die Zeile nach der aktuellen Zeile. Das . bezieht sich auf die aktuelle Zeile. Das/^[^H]/-
bedeutet die Zeile vor (-
) der nächsten Zeile, die nicht mit H beginnt.Dann ist d löschen.
quelle
uniq
ich diesen Fehler durch Aufrufen (entweder aus Vim heraus oder mithilfe der Shell) lösen. Zum einen bin ich mir ziemlich sicheruniq
, dass Zeilen, die leer / alle Leerzeichen sind, als äquivalent behandelt werden (habe es nicht getestet), aber das wäre mit einer Regex viel schwieriger zu erfassen. Es bedeutet auch, das Rad nicht neu zu erfinden, während ich versuche, die Arbeit zu erledigen.Eine Vim-basierte Antwort:
= Ersetzen Sie jede Zeile, gefolgt von sich selbst, mindestens einmal durch dieselbe Zeile.
quelle
Eine weitere, vorausgesetzt Vim 7.4.218 oder neuer:
Dies ist jedoch nicht unbedingt besser als die anderen Lösungen.
quelle
Hier ist eine Lösung basierend auf einem alten (2003) Vim (Golf) von Preben Gulberg und Piet Delport.
%g/^\v(.*)\n\1$/d
:Uniq
(entspricht:%Uniq
),:1,Uniq
(vom Anfang des Puffers bis zur aktuellen Zeile),:Uniq<cr>
(erweitert um vim in:'<,'>Uniq
):h range
)Hier ist der Code:
Hinweis: Ihre ersten Versuche waren:
quelle