kivly
kivly

Reputation: 23

How to modify a line after every 6 lines in vim

I have a file with these lines:

aaa
aaa
aaa
aaa
aaa
aaa
bbb
bbb
bbb
bbb
bbb
bbb
ccc
ccc
ccc
ccc
ccc
ccc
ddd
ddd
ddd
ddd
ddd
ddd

i want to convert this into:

aaa;100;
aaa
aaa
aaa
aaa
aaa
bbb;100;
bbb
bbb
bbb
bbb
bbb
ccc;100;
ccc
ccc
ccc
ccc
ccc
ddd;100;
ddd
ddd
ddd
ddd
ddd

Is this possible in vim in one command ?

Upvotes: 1

Views: 166

Answers (5)

Alan Gómez
Alan Gómez

Reputation: 378

You can use this:

:%s/\(^.*\)\(\(\n^.*\)\{5}\)/\1;100;\2

^.* match a single line

\(...\) group

\{5} repeater

Upvotes: 0

Lieven Keersmaekers
Lieven Keersmaekers

Reputation: 58441

Yet another one

:g/^/ if !((line('.')-1)%6)|s/$/;100;

Breakdown

  • g/^/ Global command to apply next expression on each line
  • if !((line('.')-1)%6) If the modulus of the current line equals 0
  • s/$/;100; Replace the line ending with ;100;

Upvotes: 6

René Nyffenegger
René Nyffenegger

Reputation: 40499

:%s/\v(.*)(\n.*)(\n.*)(\n.*)(\n.*)(\n.*\n)/\1;100;\2\3\4\5\6/

Upvotes: -1

Andy Ray
Andy Ray

Reputation: 32066

If the lines are all the same until the change, this is a pretty nasty Vim solution:

/\v(.*)\n\zs\1@!
:%g//norm A;100;

Traditionally in Vim you craft a search first, then use :%s//replace to replace your last search with "replace". In one line it would be:

:%g/\v(.*)\n\zs\1@!/norm A;100;

I'm so sorry. This is what happens after years of Vim use. It's not pretty.

Explanation:

Essentially we're finding lines that AREN'T duplicated on the next line, and performing an action on them, in this case, adding some text.

  • :%g/ Perform an action on a pattern (same syntax as %s)
  • \v Very magic. Makes all special characters in Vim regexes special.
  • (.*)\n any text followed by a line break. Capture the text.
  • \zs Start highlighting the match here. This will put the cursor on the next line after the match, where we will perform the action.
  • \1 The capture group from above (.*), so a new line with the same text...
  • @! But negate it! So the cursor will go to any line that is NOT duplicated by the previous line.
  • /norm A;100; Peform the normal mode command A;100; which will execute keystrokes on each line as if you were in normal mode. Regular Vim here, just append (A) text.

Upvotes: 1

lahwran
lahwran

Reputation: 597

That depends on what you mean by "one command", but you can do without manually repeating it for each item by using a macro:

  1. Position your cursor on the first line
  2. Start recording a macro named z: qz
  3. Enter insert mode at the end of the line: <shift-A>
  4. Enter the text you want: ;100;
  5. Exit insert mode: <esc>
  6. Jump down six lines: 6j
  7. Stop recording the macro: q
  8. Repeat the macro the right number more times: 3@z

Because the jumping down 6 lines is part of the macro, it will line up properly and loop through the file.

The relevant commands here are q# to start recording a macro, q to end the recording, and @# to play a recording back.

More information can be found in various places, such as the vim wiki: http://vim.wikia.com/wiki/Macros

Upvotes: 4

Related Questions