Can Vim's substitute command handle recursive pattern as sed's "t labe"?

Viewed 86

Just a random example:

aaa 01 02 03 04 05

The number of numbers behind "aaa" is unfixed. The expected result of replacement is:

aaa 01
aaa 02
aaa 03
aaa 04
aaa 05

I know how to make it with sed's "t label" or with Vim using commands like

:%s/\v%(^(\a+) .{-})@<= (\d+)/\r\1 \2/g

but I wonder is there a recursive way to handle this with Vim.

2 Answers

Using vim substitution (:s)

1 Using :s and confirmation to do the job:

:%s/\s\+/\raaa /gc

When vim asks you for confirmation, you press n then a.

2 Call functions in vim's :s command:

%s/\v((\S+)\s+\S+)(.*)/\=submatch(1).substitute(submatch(3), '\s\+',"\r".submatch(2)."&",'g')

The above command looks long, but it is pretty straightforward.

Using vim macro

If I were you, I would do it with macro in vim. Personally, I feel it would be the "vim" way:

Assume the line in your example sits in line1, and your cursor is on the first column. You press:

qqyw2f<Space>i<Enter><Ctrl-r>"<Esc>0q

To record a macro and save it in q register. Next, you can just replay the macro x times, for example:

99@q

and see how vim does the job. The total number of keystrokes to finish the job would be less than 20.

It looks like:

enter image description here

You may use

:%s/\v(\S+)(^(\S+)\s+\S+\s.{-})@<=/\r\3 \1/g

Details

  • \v - very magic mode ON
  • (\S+) - Group 1: any one or more non-whitespace chars
  • (^(\S+)\s+\S+\s.{-})@<= - that are preceded with (()@<= is a positive lookbehind construct, it is, however, counted as a group):
    • ^ - start of string
    • (\S+) - Group 3: any one or more non-whitespace chars
    • \s+ - 1+ whitespace chars
    • \S+ - 1+ non-whitespace chars
    • \s - 1 whitespace char
    • .{-} - any 0+ chars other than line break chars, as few as possible

Result:

aaa 01
aaa 02
aaa 03
aaa 04
aaa 05
Related