I would like to turn a list like this

these are
custom regex expressions 4
syntax? syntax
weird one 3
there are many many many many words in this line 3

into this

these are
custom {4}regex {4}expressions
syntax? syntax
weird {3}one
there {3}are {3}many {3}many {3}many {3}many {3}words {3}in {3}this {3}line

I know how to get rid of the trailing number ending

:%s/ \d\+$//

I know how to replace spaces

:s/ / {3}/g

but how do I combine these two? The second should only apply to lines that actually ended in a number, and use that number.

In my head this problem formed a "substitution in a substitution" thing, like this:

:%s/\(.\+\) \(\d\+\)$/\1.replace(' ', ' {\2}')/

But there is likely a better, VIM, way to solve this. Maybe my conceptualised solution is not supported.

Please how can I perform such operations?

  • 1
    Would something like this work? :g/\d$/s/ /\=' {' . matchstr(getline('.'), '\d\+$') . '}'/g This use a :g command to match only lines ending with w number and applies a substitution command using an expression composed of ' { i.e the space and the first bracket concatenated with matchstr(getline('.'), '\d\+$') which gets the number at the end of the line. You'll probably need to clean up the remaining trailing digits with :%s/\d\+$// – statox May 12 at 9:40
  • 1
    Your instinct was kinda on the right track. In general, if you have a substitution problem that can be expressed along the lines of "match a pattern then within the matched string match another pattern [and substitute]" you're often going to need sub-replace expressions . That's what statox's suggestion is using. – B Layer May 12 at 12:52
  • 2
    @BLayer would you like to post an answer? Thanks to your link i've figured out the answer ought to be :%s/\(.\+\) \(\d\+\)$/\=substitute(submatch(1), ' ', ' {' . submatch(2) . '}', 'g')/ – theonlygusti May 12 at 13:32
  • Cool. Glad it was that easy. Go ahead and post an answer yourself, if you'd like. Maybe an upvote for the answer that helped, though...? :) If you'd prefer someone else answer then I'll do it. – B Layer May 12 at 13:53
  • @theonlygusti Please turn that into an answer! That's exactly correct, that's what I came here to post, but saw you got to it already. Cheers! – filbranden May 12 at 15:00

Thanks to B Layer's guidance in the comments and his answer here I've learnt about sub-replace expressions (:help sub-replace-expression)

The command that does exactly what I need is:

:%s/\(.\+\) \(\d\+\)$/\=substitute(submatch(1), ' ', ' {' . submatch(2) . '}', 'g')/

In the replacement part we use the special operator \= which tells Vim to treat everything that follows as an expression, evaluate it, and use the result as the replacement of the matched text

Thanks https://vi.stackexchange.com/a/20706/9024

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.