How would you go about marking all of the lines in a buffer that are exact duplicates of other lines? By marking them, I mean highlighting them or adding a character or something. I want to retain the order of the lines in the buffer.
Before:
foo
bar
foo
baz
After:
foo*
bar
foo*
baz
As an ex one-liner:
:syn clear Repeat | g/^\(.*\)\n\ze\%(.*\n\)*\1$/exe 'syn match Repeat "^' . escape(getline('.'), '".\^$*[]') . '$"' | nohlsearch
This uses the Repeat group to highlight the repeated lines.
Breaking it down:
syn clear Repeat:: remove any previously found repeatsg/^\(.*\)\n\ze\%(.*\n\)*\1$/:: for any line that is repeated later in the file- the regex
^\(.*\)\n:: a full line\ze:: end of match - verify the rest of the pattern, but don't consume the matched text (positive lookahead)\%(.*\n\)*:: any number of full lines\1$:: a full line repeat of the matched full line
exe 'syn match Repeat "^' . escape(getline('.'), '".\^$*[]') . '$"':: add full lines that match this to theRepeatsyntax groupexe:: execute the given string as an ex commandgetline('.'):: the contents of the current line matched byg//escape(..., '".\^$*[]'):: escape the given characters with backslashes to make a legit regexsyn match Repeat "^...$":: add the given string to theRepeatsyntax group
- the regex
nohlsearch:: remove highlighting from the search done forg//
Justin's non-regex method is probably faster:
function! HighlightRepeats() range
let lineCounts = {}
let lineNum = a:firstline
while lineNum <= a:lastline
let lineText = getline(lineNum)
if lineText != ""
let lineCounts[lineText] = (has_key(lineCounts, lineText) ? lineCounts[lineText] : 0) + 1
endif
let lineNum = lineNum + 1
endwhile
exe 'syn clear Repeat'
for lineText in keys(lineCounts)
if lineCounts[lineText] >= 2
exe 'syn match Repeat "^' . escape(lineText, '".\^$*[]') . '$"'
endif
endfor
endfunction
command! -range=% HighlightRepeats <line1>,<line2>call HighlightRepeats()
None of the answers above worked for me so this is what I do:
- Sort the file using
:sort - Execute command
:g/^\(.*\)$\n\1$/p
:sortand save it infile1.:sort uand save it infile2.gvimdiffortkdiffthe two files.
Why not use:
V*
in normal mode.
It simply searches all matches of current line, thus highlighting them (if the setting is enabled, which I think it's the default) Besides, you can then use
n
To navigate through the matches
Run through the list once, make a map of each string and how many times it occurs. Loop through it again, and append your * to any string that has a value of more than one in the map.
Try:
:%s:^\(.\+\)\n\1:\1*\r\1:
Hope this works.
Update: next try.
:%s:^\(.\+\)$\(\_.\+\)^\1$:\1\r\2\r\1*:
来源:https://stackoverflow.com/questions/1268032/how-can-i-mark-highlight-duplicate-lines-in-vi-editor