110

In Vim, I know we can use ~ to capitalize a single char (as mentioned in this question), but is there a way to capitalize the first letter of each word in a selection using Vim?

For example, if I would like to change this

hello world from stack overflow

to

Hello World From Stack Overflow

how should I do it in Vim?

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
keelar
  • 5,814
  • 7
  • 40
  • 79
  • 1
    Can also be done with [sed](https://superuser.com/a/749174/86708) – jpaugh Nov 08 '18 at 16:49
  • 1
    For anyone else who lands here but wants to capitalize the first letter in a VERTICAL selection covering multiple lines, just do `Ctrl+V`, make your vertical selection to select the first letters, then type `~` and every first letter in each line will now be capitalized. – Eric Mutta Aug 05 '23 at 13:59

9 Answers9

225

You can use the following substitution:

s/\<./\u&/g
  • \< matches the start of a word
  • . matches the first character of a word
  • \u tells Vim to uppercase the following character in the substitution string (&)
  • & means substitute whatever was matched on the left-hand side
  • g means substitute all matches, not only the first
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
70

:help case says:

To turn one line into title caps, make every first letter of a word
uppercase:
    : s/\v<(.)(\w*)/\u\1\L\2/g

Explanation:

:                      # Enter ex command line mode.

space                  # The space after the colon means that there is no
                       # address range i.e. line,line or % for entire
                       # file.

s/pattern/result/g     # The overall search and replace command uses
                       # forward slashes.  The g means to apply the
                       # change to every thing on the line. If there
                       # g is missing, then change just the first match
                       # is changed.

The pattern portion has this meaning:

\v                     # Means to enter very magic mode.
<                      # Find the beginning of a word boundary.
(.)                    # The first () construct is a capture group.
                       # Inside the () a single ., dot, means match any
                       #  character.
(\w*)                  # The second () capture group contains \w*. This
                       # means find one or more word characters. \w* is
                       # shorthand for [a-zA-Z0-9_].

The result or replacement portion has this meaning:

\u                     # Means to uppercase the following character.
\1                     # Each () capture group is assigned a number
                       # from 1 to 9. \1 or back slash one says use what
                       # I captured in the first capture group.
\L                     # Means to lowercase all the following characters.
\2                     # Use the second capture group

Result:

ROPER STATE PARK
Roper State Park

An alternate to the very magic mode:

: % s/\<\(.\)\(\w*\)/\u\1\L\2/g
# Each capture group requires a backslash to enable their meta
# character meaning i.e. "\(\)" versus "()".
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
ernix
  • 3,442
  • 1
  • 17
  • 23
  • 3
    This was the most interesting answer to me. I'd never seen the very magic mode. I thought I'd document the answer after I understood the answer. – Greg Jan 17 '15 at 21:45
  • Additionally, this answer handles all lower case, all upper case, or mixed case strings. – Greg Jan 17 '15 at 22:04
  • I used \S instead of \w for non-ascii characters: `s/\v<(.)(\S*)/\u\1\L\2/g` :-) – Regisz Nov 11 '22 at 12:10
14

The Vim Tips Wiki has a TwiddleCase mapping that toggles the visual selection to lower case, UPPER CASE, and Title Case.

If you add the TwiddleCase function to your .vimrc, then you just visually select the desired text and press the tilde character ~ to cycle through each case.

Matthew Rankin
  • 457,139
  • 39
  • 126
  • 163
Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
2

Try This regex ..

s/ \w/ \u&/g
Krishna
  • 381
  • 2
  • 9
  • I liked the answer with the use of the `&` but it does not work if your string string is mixed case to begin with or all uppercase to begin with. – Greg Jan 17 '15 at 21:49
2

Option 1. -- This mapping maps the key q to capitalize the letter at the cursor position, and then it moves to the start of the next word:

:map q gUlw

To use this, put the cursor at the start of the line and hit q once for each word to capitalize the first letter. If you want to leave the first letter the way it is, hit w instead to move to the next word.

Option 2. -- This mappings maps the key q to invert the case of the letter at the cursor position, and then it moves to the start of the next word:

:map q ~w

To use this, put the cursor at the start of the line hit q once for each word to invert the case of the first letter. If you want to leave the first letter the way it is, hit w instead to move to the next word.

Unmap mapping. -- To unmap (delete) the mapping assigned to the q key:

:unmap q
D. Ben Knoble
  • 4,273
  • 1
  • 20
  • 38
Michael
  • 21
  • 1
1

There is also the very useful vim-titlecase plugin for this.

Serge Stroobandt
  • 28,495
  • 9
  • 107
  • 102
1

To restrict the modification to the visual selection we have to use something like:

:'<,'>s/\%V\<.\%V/\u&/g

\%V ............... see help for this
SergioAraujo
  • 11,069
  • 3
  • 50
  • 40
0

The following mapping causes g~ to "title case" selected text:

vnoremap g~ "tc<C-r>=substitute(@t, '\v<(.)(\S*)', '\u\1\L\2', 'g')<CR><Esc>
aggu
  • 93
  • 2
  • 7
0

The fastest way to do what you want on a random string and retain some control of words that you generally do not want capitalized (eg: articles like of/and) is to use ~ to change the case of the first word and then w. to select and change each word in turn, bearing in mind you can skip the . (repeat char) if you don't want to capitalize a particular word.

chipfall
  • 300
  • 2
  • 6