Search code examples
regexvimreplacecapitalize

Vim, regex search and replace in all buffers with letter case changes


I am working on a LaTeX document. I need to reformat the subsection titles that I have in all open buffers in vim.

Normally, I do a command like bufdo %s/pattern/replacement/g | update inside of vim when I need to modify all buffers. That is what I intend to do again. All I need help with are the pattern and replacement strings.

The strings that I need to match have the following format:

  • \subsection{word}
  • \subsection{some words}
  • \subsection{some Words CAPitalized weirdlY}
  • \subsection{and some with $\control$ sequences in them}

The resulting search and replace should affect the strings to be like below:

  • \subsection{Word}
  • \subsection{Some Words}
  • \subsection{Some Words Capitalized Weirdly}
  • \subsection{And Some With $\control$ Sequences In Them}

So far the search strings that I have tried are:

  1. %s/\\subsection{\(.\)\(\w*\)}/\\subsection{\u\1\L\2}/gc.
  2. %s/\\subsection{\v<\(.\)\(\w*\)}/\\subsection{\u\1\L\2}/gc

Number 1 only matches single words and turns them into the correct format.

Number 2 does not work. My goal was to combine the sequence referenced in the SO answer from the links below with my needs but I guess I am not using it correctly.


The resources that I am trying to use to figure this out:

Note: If I have to go back through and retype the $\control characters if the replacement also capitalizes them, I would be ok with that.


Solution

  • bufdo %s/\%(\\subsection{.*\)\@<=\%(.*}\)\@=\<\(\w\)\(\w*\)\>/\u\1\L\2/gc
    

    This should capitalise everything inside \subsection{....} blocks, unfortunately including inside math sequences, but it will ask you for confirmation each time. The search is a bit more involved than in the linked "previous question":

    \%(     non-capturing group
    \\...{    literal `\subsection{`
    .*        any number of characters
    \)      end of group
    \@<=    zero-width lookbehind
    
    \%(     non-capturing group
    .*        any number of characters
    \)      end of group
    \@=     zero-width lookahead
    
    \<      zero-width start of word
    \(      start of 1st group
    \w        word letter
    \)      end of group
    \(      start of 2nd group
    \w*       any number of letters
    \)      end of group
    \>      zero-width end of word