I think the following command should work :
:%s/^\(.*\)\(\n\1\)\+$/\1/
Explanation :
We use the substitution command on the whole file to change pattern
into string
:
:%s/pattern/string/
Here pattern
is ^\(.*\)\(\n\1\)\+$
and string
is \1
.
pattern
can be broken down like this :
^\(subpattern1\)\(subpattern2\)\+$
^
and $
match respectively a beginning of line and an end of line.
\(
and \)
are used to enclose subpattern1
so that we can refer to it later by the special number \1
.
They are also used to enclose subpattern2
so that we can repeat it 1 or more times with the quantifier \+
.
subpattern1
is .*
.
is a metacharacter matching any character except new line and *
is a quantifier that matches the last character 0, 1 or more times.
So .*
matches any text containing no new line.
subpattern2
is \n\1
\n
matches a new line and \1
matches the same text that was matched inside the first \(
, \)
which here is subpattern1
.
So pattern
can be read like this :
a beginning of line (^
) followed by any text containing no new line (.*
) followed by a new line (\n
) then the same text (\1
), the latter two being repeated one or more times (\+
), and finally an end of line ($
).
Wherever pattern
is matched (a block of identical lines), the substitution command replaces it with string
which here is \1
(the first line of the block).
If you want to see which blocks of lines will be affected without changing anything in your file, you can enable the hlsearch
option and add the n
substitution flag at the end of the command :
:%s/^\(.*\)\(\n\1\)\+$/\1/n
For more granular control, you can also ask for a confirmation before changing each block of lines by adding the c
substitution flag instead :
:%s/^\(.*\)\(\n\1\)\+$/\1/c
For more information on the substitution command read :help :s
,
for the substitution flags :help s_flags
,
for the various metacharacters and quantifiers read :help pattern-atoms
,
and for regular expressions in vim read this.
Edit: Wildcard fixed a problem in the command by adding a $
at the end of pattern
.
Also BloodGain has a shorter and more readable version of the same command.