This is not exactly what you want, but you could visually select your lines, then run this global command:
g/^/exe 'norm! "adiwD' | exe 'norm! '.@a.'p'
├───┘│ ├────┘
│ │ └ paste unnamed register as many times as the number in register `a`
│ └ delete word in unnamed register
└ delete count in register `a`
There will we be an extra space in front of each line; to remove it:
:'<,'>s/^ /
Edit:
Peter Rincker has a shorter solution.
Broken down:
:g/^/exe 'norm x'|exe 'norm D'.@@.'p0x'
│ │ ├───┘├┘
│ │ │ └ delete extra space at the start of the line
│ │ └ paste word count times
│ └ delete word in unnamed register
└ delete count in unnamed register
To make it more reliable, you could suffix :norm
with a bang (to ignore custom mappings), and delete the count with diw
(to handle multi-digit numbers):
:g/^/exe 'norm! diw'|exe 'norm! D'.@@.'p0x'
^ ^^^ ^
Alternatively, select your lines, then run this substitution command:
s/\(\d\+\)\s\+\(\k\+\)/\=repeat(submatch(2).' ', str2nr(submatch(1)))
├──────┘ ├──────┘ ├┘│ ├─────────────┘ ├─────────────────┘
│ │ │ │ │ └ as many times as the count in the capturing group 1
│ │ │ │ └ the capturing group 2 (word) followed by a space
│ │ │ └ repeat the next string
│ │ └ use evaluation of next expression for the replacement
│ └ capture word
└ capture count
There will we be an extra space at the end of each line; to remove it:
:'<,'>s/ $/
I'm not sure the call to str2nr() is required.
If the number starts with a leading 0
, Vim will take it as octal.
This is why, without str2nr()
, the line:
010 foo
would be turned into:
foo foo foo foo foo foo foo foo
Whereas, with str2nr()
, it will be turned into:
foo foo foo foo foo foo foo foo foo foo
Here is a more detailed explanation.
But if the OP is working with octal numbers, then you're right, and they should remove str2nr()
.
On the :s/// case you can even handle plurals easily with an s\? at the end of the match, outside the group.
You're right, although, I think you would need to also add s\@<!
at the end of the second capturing group:
s/\(\d\+\)\s\+\(\k\+s\@<!\)s\=/\=repeat(submatch(2).' ', str2nr(submatch(1)))
^^^^ ^^^
As explained by Christian Brabandt, you could also use \{-}
and \>
:
s/\(\d\+\)\s\+\(\k\{-}\)s\=\>/\=repeat(submatch(2).' ', str2nr(submatch(1)))
^^^^ ^^
But no solution will correctly deal with words whose plural form adds more than a single s
, like peach
whose plural form adds e
and s
. I guess that for such words, you will have to fix them manually afterward.
Also, suggestion to use \v in your regex, do you don't need to backslash all parens and plusses.
For various reasons, I prefer \m
, but if it helps, the command substitution can be rewritten like this:
s/\v(\d+)\s+(\k+s@<!)s=/\=repeat(submatch(2).' ', str2nr(submatch(1)))