Home > Blockchain >  Backreferencing wildcard matches in vim substitution
Backreferencing wildcard matches in vim substitution

Time:08-30

I have a file with three lines.

HelloStackOverflow
ThisIsMyFirstPost
OnThisWebsite

I want it to look like this.

HELLO_STACK_OVERFLOW
THIS_IS_MY_FIRST_POST
ON_THIS_WEBSITE

Is there a way to do this using Vim's substitution? I currently have this.

:%s/^\([A-Z][a-z]*\)*\([A-Z][a-z]*\)$/\U\1_\2/g

The first group captures all words up to the last in each line, and the second group captures the last. Can I "expand" the backreference to the multiple matches of the first group, so _ can be put after each one? Currently, it produces this.

STACK_OVERFLOW
FIRST_POST
THIS_WEBSITE

(\1 gives the last wildcard match)

CodePudding user response:

As you have a * after the first capture group, only the last of those repetitions will actually get in the first capture group. Moreover, this repetition will make it impossible to insert underscores earlier on in the phrase.

I would make that a ? instead of *. The idea is that you only want to capture something (one word) when it is the first word of the phrase, but for any other position in the input, you don't want to match anything here.

So a few changes are needed:

  • Change the * after the first capture group to ?
  • The ^ should move inside the capture group, so the ? applies to it.
  • The $ at the end should be removed as otherwise you cannot have multiple matches on the same line.

That gives:

:%s/\(^[A-Z][a-z]*\)?\([A-Z][a-z]*\)/\U\1_\2/g
  • Related