How can I capitalize the first letter of each word in a string?

The .title() method of a string (either ASCII or Unicode is fine) does this:

>>> "hello world".title()
'Hello World'
>>> u"hello world".title()
u'Hello World'

However, look out for strings with embedded apostrophes, as noted in the docs.

The algorithm uses a simple language-independent definition of a word as groups of consecutive letters. The definition works in many contexts but it means that apostrophes in contractions and possessives form word boundaries, which may not be the desired result:

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"

The .title() method can't work well,

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"

Try string.capwords() method,

import string
string.capwords("they're bill's friends from the UK")
>>>"They're Bill's Friends From The Uk"

From the Python documentation on capwords:

Split the argument into words using str.split(), capitalize each word using str.capitalize(), and join the capitalized words using str.join(). If the optional second argument sep is absent or None, runs of whitespace characters are replaced by a single space and leading and trailing whitespace are removed, otherwise sep is used to split and join the words.


Here is a summary of different ways to do it, and some pitfalls to watch out for

They will work for all these inputs:

""           => ""       
"a b c"      => "A B C"             
"foO baR"    => "FoO BaR"      
"foo    bar" => "Foo    Bar"   
"foo's bar"  => "Foo's Bar"    
"foo's1bar"  => "Foo's1bar"    
"foo 1bar"   => "Foo 1bar"     
  • Splitting the sentence into words and capitalizing the first letter then join it back together:

     # Be careful with multiple spaces, and empty strings
     # for empty words w[0] would cause an index error, 
     # but with w[:1] we get an empty string as desired
     def cap_sentence(s):
       return ' '.join(w[:1].upper() + w[1:] for w in s.split(' '))
    
  • Without splitting the string, checking blank spaces to find the start of a word

      def cap_sentence(s):
        return ''.join( (c.upper() if i == 0 or s[i-1] == ' ' else c) for i, c in enumerate(s) )
    
  • Or using generators:

      # Iterate through each of the characters in the string 
      # and capitalize the first char and any char after a blank space
      from itertools import chain 
      def cap_sentence(s):
        return ''.join( (c.upper() if prev == ' ' else c) for c, prev in zip(s, chain(' ', s)) )
    
  • Using regular expressions, from steveha's answer:

      # match the beginning of the string or a space, followed by a non-space
      import re
      def cap_sentence(s):
        return re.sub("(^|\s)(\S)", lambda m: m.group(1) + m.group(2).upper(), s)
    

Now, these are some other answers that were posted, and inputs for which they don't work as expected if we define a word as being the start of the sentence or anything after a blank space:

  • .title()

      return s.title()
    
    # Undesired outputs: 
    "foO baR"    => "Foo Bar"     
    "foo's bar"  => "Foo'S Bar"   
    "foo's1bar"  => "Foo'S1Bar"       
    "foo 1bar"   => "Foo 1Bar"        
    

  • .capitalize() or .capwords()

      return ' '.join(w.capitalize() for w in s.split())    
    # or
      import string
      return string.capwords(s)
    
    # Undesired outputs:
    "foO baR"    => "Foo Bar"      
    "foo    bar" => "Foo Bar"      
    

    using ' ' for the split will fix the second output, but not the first

      return ' '.join(w.capitalize() for w in s.split(' '))    
    # or
      import string
      return string.capwords(s, ' ')
    
    # Undesired outputs:
    "foO baR"    => "Foo Bar"      
    

  • .upper()

    Be careful with multiple blank spaces, this gets fixed by using ' ' for the split (like shown at the top of the answer)

      return ' '.join(w[0].upper() + w[1:] for w in s.split())
    # Undesired outputs:
    "foo    bar" => "Foo Bar"                 
    

Just because this sort of thing is fun for me, here are two more solutions.

Split into words, initial-cap each word from the split groups, and rejoin. This will change the white space separating the words into a single white space, no matter what it was.

s = 'the brown fox'
lst = [word[0].upper() + word[1:] for word in s.split()]
s = " ".join(lst)

EDIT: I don't remember what I was thinking back when I wrote the above code, but there is no need to build an explicit list; we can use a generator expression to do it in lazy fashion. So here is a better solution:

s = 'the brown fox'
s = ' '.join(word[0].upper() + word[1:] for word in s.split())

Use a regular expression to match the beginning of the string, or white space separating words, plus a single non-whitespace character; use parentheses to mark "match groups". Write a function that takes a match object, and returns the white space match group unchanged and the non-whitespace character match group in upper case. Then use re.sub() to replace the patterns. This one does not have the punctuation problems of the first solution, nor does it redo the white space like my first solution. This one produces the best result.

import re
s = 'the brown fox'

def repl_func(m):
    """process regular expression match groups for word upper-casing problem"""
    return m.group(1) + m.group(2).upper()

s = re.sub("(^|\s)(\S)", repl_func, s)


>>> re.sub("(^|\s)(\S)", repl_func, s)
"They're Bill's Friends From The UK"

I'm glad I researched this answer. I had no idea that re.sub() could take a function! You can do nontrivial processing inside re.sub() to produce the final result!