Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I mark/highlight duplicate lines in VI editor?

Tags:

vim

duplicates

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 
like image 425
Brian Carper Avatar asked Aug 12 '09 18:08

Brian Carper


People also ask

How do you duplicate a line in vi?

Directions: Press the ESC key to be sure you are in vi Command mode. Place the cursor on the line you wish to copy. Type yy to copy the line.

How do you check for duplicate lines in Linux?

The uniq command in Linux is used to display identical lines in a text file. This command can be helpful if you want to remove duplicate words or strings from a text file. Since the uniq command matches adjacent lines for finding redundant copies, it only works with sorted text files.

How do you copy a line under the cursor in Normal mode?

For example, to copy two lines from the current position of the cursor, press (in normal mode, or escape mode), y2-1k which is equivalent to y1k .


2 Answers

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 repeats
  • g/^\(.*\)\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 the Repeat syntax group
      • exe :: execute the given string as an ex command
      • getline('.') :: the contents of the current line matched by g//
      • escape(..., '".\^$*[]') :: escape the given characters with backslashes to make a legit regex
      • syn match Repeat "^...$" :: add the given string to the Repeat syntax group
  • nohlsearch :: remove highlighting from the search done for g//

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() 
like image 74
rampion Avatar answered Sep 24 '22 17:09

rampion


None of the answers above worked for me so this is what I do:

  1. Sort the file using :sort
  2. Execute command :g/^\(.*\)$\n\1$/p
like image 32
Krisztián Balla Avatar answered Sep 22 '22 17:09

Krisztián Balla