813
s = 'the brown fox'

...do something here...

s should be:

'The Brown Fox'

What's the easiest way to do this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
TIMEX
  • 259,804
  • 351
  • 777
  • 1,080

24 Answers24

1323

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"
Community
  • 1
  • 1
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 1
    you are demonstrating `str.title()`, not `string.title()`. Python 2's `unicode.title()` does the same for unicode strings. – u0b34a0f6ae Oct 11 '09 at 10:23
  • 84
    I avoid the possessive problem with something like `" ".join(w.capitalize() for w in s.split())` – krethika Apr 22 '13 at 19:12
  • 5
    this isn't safe for most strings because every word even possessive gets uppercased. –  Aug 29 '14 at 10:14
  • 16
    There is a problem with string.title(). When you use, for example, `"e g 3b"`, the desired result would be `"E G 3b"`. However, `"e g 3b".title()` returns `"E G 3B"`. – Soerendip Nov 11 '16 at 18:06
  • 13
    Keep in mind that this will cause this too: `In [2]: 'tEst'.title() Out[2]: 'Test' ` – Jonas Libbrecht Nov 14 '16 at 10:05
  • 6
    Great answer, and comments highlight that in python not everything behaves the way you need it to, but there's always convenient ways to make it so. The most convenient way is often importing a purpose-built library, such as [python-titlecase](https://github.com/ppannuto/python-titlecase) – Aaron3468 Mar 22 '18 at 05:42
  • `title()` could have undesired outputs, look at my answer below where I explain some examples of it and alternatives https://stackoverflow.com/a/42500863/3577695 – aljgom Mar 10 '21 at 10:38
260

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Chen Houwu
  • 2,601
  • 1
  • 12
  • 2
  • 5
    Capwords is still lacking and does not handle something such as `"There once was a string with an 'that had words right after it and then closed'"`. With this example all the worlds except for `that` are capitalized as expected. The results being `"There Once Was A String With An 'that Had Words Right After It And Then Closed'"` – devonbleibtrey Mar 25 '16 at 21:53
  • 3
    Still, this works better than `title()` for normal situations. In my situation, `title()` returns a bad output for names with accents or dieresis, while `capwords()` handled it correctly. – houcros Sep 20 '16 at 11:04
  • 4
    Good, but it still messes up the "Uk/UK" distinction – Jonath P Nov 17 '18 at 15:54
  • 2
    @Chen Houwu, Uk/UK is a perfect counter example. How would one prevent Python from lowercasing existing capital letters using a similar method? – h0r53 Jun 10 '20 at 18:50
127

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!

steveha
  • 74,789
  • 21
  • 92
  • 117
  • 3
    +1 for the solution using slices. I needed something that would capitalize first letters without altering the capitalization of the rest of the words (e.g. Foo becomes foo, but FOO becomes fOO). This was perfect. – TomNysetvold May 23 '12 at 15:13
  • 3
    capitalize returns its first character capitalized and the rest lowercased – Vanuan Dec 01 '12 at 20:34
  • 1
    @Vanuan, you are right! The doc string description made me think all it did was capitalize the first letter, but you are right about what it actually does. I'll edit the answer. Thank you for the heads-up. – steveha Dec 03 '12 at 06:23
  • 1
    This appears to be what `string.capwords` does, according to the documentation in Chen Houwu's answer. – Adrian Keister Oct 11 '19 at 17:58
  • 2
    Something to note in the above answer, instead of using s.split(), i think it's better to use s.split(' '). This is because incase the string has some double spaces and you wish to maintain those double spaces on joining, s.plit(' ') will help you maintain the spaces while s.split() won't – manpikin Feb 03 '20 at 20:03
47

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"                 
    
aljgom
  • 7,879
  • 3
  • 33
  • 28
  • 2
    +1 for a comprehensive summary. I am looking for a way to only capitalize a word following a number (not every word). Could you make an addition to your answer that demonstrates this? E.g. `lower 123 upper` should return `lower 123 Upper`, where the `upper` is capitalized as it follows a number. I know it goes beyond the scope of the OP's question but a nice add-on to your already extensive answer. Thanks in advance. – ProGrammer Jan 07 '18 at 03:56
  • 1
    You could modify some of the above methods to suit your needs in this case. However, I would not add it as part of the answer since it's not what most people are looking for. I would use the regex version for it, and use `"([0-9]+)(\s+.)"` instead of `"(^|\s)(\S)"` (match one or more numbers, followed by one or more spaces, and any char after), or `"([0-9]+)(\s*.)"` if you want to capitalize the character after 'zero or more' spaces after the number – aljgom Jan 07 '18 at 21:53
  • 1
    I'll be sure to look into it, that made my think about another special case: How would you modify the snippets above to take a string, e.g. `WW1 - the great war` and output `WW1 - The Great War` instead of `Ww1 ...`. See the issue with abbreviations? Would you be willing to add something that demonstrates this case? I have been wondering about this for a while now and can't think of a way to do it. – ProGrammer Jan 08 '18 at 22:38
  • 1
    The first ways stated above don't change letters that were already capitalized in the input string, so `WW1` would output as `WW1` – aljgom Jan 10 '18 at 00:45
  • 2
    thanks a lot, I was looking for something that would address exactly this problem in this way, really good answer, everything well explained "parameter fooR" returns as "Parameter FooR" now I can finally stop destroying my pinky finger against the shift key cheers from the future – Boris Jul 26 '21 at 03:04
  • This worked for me result = ' '.join(elem.capitalize() for elem in s.split(' ')) – Duc Toan Pham Jun 06 '22 at 04:41
17

Copy-paste-ready version of @jibberia anwser:

def capitalize(line):
    return ' '.join(s[:1].upper() + s[1:] for s in line.split(' '))
ayhan
  • 70,170
  • 20
  • 182
  • 203
Konstantin Spirin
  • 20,609
  • 15
  • 72
  • 90
  • 2
    No need to build a list. `str.join` accepts generators. – warvariuc Jan 27 '15 at 08:04
  • @warvariuc how would you change this code to leverage generators? – Konstantin Spirin Jan 27 '15 at 23:40
  • 1
    Just remove the square brackets, like it's done [here](http://stackoverflow.com/a/1549983/248296) – warvariuc Jan 28 '15 at 06:34
  • 1
    Though @warvariuc is perfect in mentioning that `join` accepts gen exps, In the case of `str.join` particularly, it is generally preferred to use a list comprehension. This is because `join` iterates twice over the argument, and hence it is faster to provide a ready-to-go list rather than a generator. – Bhargav Rao Aug 26 '16 at 14:28
  • 1
    @BhargavRao why would `str.join` need to iterate twice over the argument? I just checked -- it doesn't. Though for small sequences list comprehension is faster indeed. – warvariuc Aug 27 '16 at 07:19
  • @warvariuc It does iterate twice. You can refer to [Ray's answer](http://stackoverflow.com/a/9061024/4099593) on the same. (As you yourself mentioned, the speed difference is quite perceivable even for small lists!) – Bhargav Rao Aug 27 '16 at 18:08
17

Why do you complicate your life with joins and for loops when the solution is simple and safe??

Just do this:

string = "the brown fox"
string[0].upper()+string[1:]
Brad Larson
  • 170,088
  • 45
  • 397
  • 571
12

If only you want the first letter:

>>> 'hello world'.capitalize()
'Hello world'

But to capitalize each word:

>>> 'hello world'.title()
'Hello World'
Daniel Holmes
  • 1,952
  • 2
  • 17
  • 28
Zahran
  • 419
  • 4
  • 10
11

If str.title() doesn't work for you, do the capitalization yourself.

  1. Split the string into a list of words
  2. Capitalize the first letter of each word
  3. Join the words into a single string

One-liner:

>>> ' '.join([s[0].upper() + s[1:] for s in "they're bill's friends from the UK".split(' ')])
"They're Bill's Friends From The UK"

Clear example:

input = "they're bill's friends from the UK"
words = input.split(' ')
capitalized_words = []
for word in words:
    title_case_word = word[0].upper() + word[1:]
    capitalized_words.append(title_case_word)
output = ' '.join(capitalized_words)
jibberia
  • 420
  • 5
  • 9
  • 1
    One point of interest with this solution is that you lose any special whitespace. May not be important depending on context. – mklauber Oct 17 '11 at 19:25
  • Worth pointing out, this fails if the sentence or set of words being capitalized contains a single character word like "a" or "I." – Nathan Nov 02 '20 at 17:51
9

An empty string will raise an error if you access [1:]. Therefore I would use:

def my_uppercase(title):
    if not title:
       return ''
    return title[0].upper() + title[1:]

to uppercase the first letter only.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Wim Feijen
  • 788
  • 7
  • 9
  • 1
    Isn't that what `str.capitalize` is for? – Eugene Pakhomov Nov 07 '17 at 17:20
  • 4
    @Eugene, yes but unfortunately, capitalize lowercases all other letters which might not be desirable. :/ – Wim Feijen Dec 12 '17 at 08:46
  • 1
    `return title[:1].upper() + title[1:]` would also take care of that problem since slicing the empty string like that would give 2 empty strings, joined together make an empty string which is returned – aljgom Jan 07 '18 at 21:42
7

Although all the answers are already satisfactory, I'll try to cover the two extra cases along with the all the previous case.

if the spaces are not uniform and you want to maintain the same

string = hello    world i  am    here.

if all the string are not starting from alphabets

string = 1 w 2 r 3g

Here you can use this:

def solve(s):
    a = s.split(' ')
    for i in range(len(a)):
        a[i]= a[i].capitalize()
    return ' '.join(a)

This will give you:

output = Hello    World I  Am    Here
output = 1 W 2 R 3g
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amit Gupta
  • 2,698
  • 4
  • 24
  • 37
  • 2
    Thanks for highlighting the case of non-uniform spaces. Some answers above use s.split() instead of s.split(' '). It is important to note that for non-uniform spaces, using s.split(' ') will ensure that the non-uniform spaces are maintained! Thanks again – manpikin Feb 03 '20 at 20:06
  • This perfectly works for words with uneven spaces or words starting with some digit. Thanks :) – Amresh Giri Apr 21 '20 at 20:24
6

As Mark pointed out, you should use .title():

"MyAwesomeString".title()

However, if would like to make the first letter uppercase inside a Django template, you could use this:

{{ "MyAwesomeString"|title }}

Or using a variable:

{{ myvar|title }}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
chuckfinley
  • 2,577
  • 10
  • 32
  • 42
5

If you will use the method .title(), then the letters after ' will also become uppercase. Like this:

>>> "hello world's".title()
"Hello World'S"

To avoid this, use the capwords function from the string library. Like this:

>>> import string
>>> string.capwords("hello world's")
"Hello World's"
4

The suggested method str.title() does not work in all cases. For example:

string = "a b 3c"
string.title()
> "A B 3C"

instead of "A B 3c".

I think, it is better to do something like this:

def capitalize_words(string):
    words = string.split(" ") # just change the split(" ") method
    return ' '.join([word.capitalize() for word in words])

capitalize_words(string)
>'A B 3c'
Community
  • 1
  • 1
Soerendip
  • 7,684
  • 15
  • 61
  • 128
2

To capitalize words...

str = "this is string example....  wow!!!";
print "str.title() : ", str.title();

@Gary02127 comment, the below solution works with title with apostrophe

import re

def titlecase(s):
    return re.sub(r"[A-Za-z]+('[A-Za-z]+)?", lambda mo: mo.group(0)[0].upper() + mo.group(0)[1:].lower(), s)

text = "He's an engineer, isn't he? SnippetBucket.com "
print(titlecase(text))
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tejas Tank
  • 1,100
  • 2
  • 16
  • 28
2

The .title() method won't work in all test cases, so using .capitalize(), .replace() and .split() together is the best choice to capitalize the first letter of each word.

eg: def caps(y):

     k=y.split()
     for i in k:
        y=y.replace(i,i.capitalize())
     return y
Augustine Jose
  • 1,235
  • 8
  • 8
2

You can try this. simple and neat.

def cap_each(string):
    list_of_words = string.split(" ")

    for word in list_of_words:
        list_of_words[list_of_words.index(word)] = word.capitalize()

    return " ".join(list_of_words)
Omar
  • 403
  • 7
  • 11
2

You can use title() method to capitalize each word in a string in Python:

string = "this is a test string"
capitalized_string = string.title()
print(capitalized_string)

Output:

This Is A Test String
Haris
  • 372
  • 3
  • 16
1

Don't overlook the preservation of white space. If you want to process 'fred flinstone' and you get 'Fred Flinstone' instead of 'Fred Flinstone', you've corrupted your white space. Some of the above solutions will lose white space. Here's a solution that's good for Python 2 and 3 and preserves white space.

def propercase(s):
    return ''.join(map(''.capitalize, re.split(r'(\s+)', s)))
GaryMBloom
  • 5,350
  • 1
  • 24
  • 32
0

A quick function worked for Python 3

Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> capitalizeFirtChar = lambda s: s[:1].upper() + s[1:]
>>> print(capitalizeFirtChar('помните своих Предковъ. Сражайся за Правду и Справедливость!'))
Помните своих Предковъ. Сражайся за Правду и Справедливость!
>>> print(capitalizeFirtChar('хай живе вільна Україна! Хай живе Любовь поміж нас.'))
Хай живе вільна Україна! Хай живе Любовь поміж нас.
>>> print(capitalizeFirtChar('faith and Labour make Dreams come true.'))
Faith and Labour make Dreams come true.
PADYMKO
  • 4,217
  • 2
  • 36
  • 41
  • This answer only capitalizes the first letter of the sentence. The question asked to capitalize the first letter of *each word* in a sentence – aljgom Mar 11 '22 at 21:57
0

Capitalize string with non-uniform spaces

I would like to add to @Amit Gupta's point of non-uniform spaces:

From the original question, we would like to capitalize every word in the string s = 'the brown fox'. What if the string was s = 'the brown fox' with non-uniform spaces.

def solve(s):
    # If you want to maintain the spaces in the string, s = 'the brown      fox'
    # Use s.split(' ') instead of s.split().
    # s.split() returns ['the', 'brown', 'fox']
    # while s.split(' ') returns ['the', 'brown', '', '', '', '', '', 'fox']
    capitalized_word_list = [word.capitalize() for word in s.split(' ')]
    return ' '.join(capitalized_word_list)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
manpikin
  • 2,200
  • 1
  • 19
  • 19
  • .. your code fails to compensate for tabs if its not whitespaces between brown and fox ;-) – ZF007 Mar 26 '20 at 09:21
0

Easiest solution for your question, it worked in my case:

import string
def solve(s):
    return string.capwords(s,' ') 
    
s=input()
res=solve(s)
print(res)
David Buck
  • 3,752
  • 35
  • 31
  • 35
0

Another oneline solution could be:

" ".join(map(lambda d: d.capitalize(), word.split(' ')))
  • There are **21 existing answers** to this question, including a top-voted, accepted answer with over **twelve hundred votes**. Are you _certain_ your solution hasn't already been given? If not, why do you believe your approach improves upon the existing proposals, which have been validated by the community? Offering an explanation is _always_ useful on Stack Overflow, but it's _especially_ important where the question has been resolved to the satisfaction of both the OP and the community. Help readers out by explaining what your answer does different and when it might be preferred. – Jeremy Caney Feb 15 '22 at 01:22
  • Sorry @JeremyCaney but I didn't see this solution in another comment. Although, I think this site has 2 options over the answers: vote or unvote. If you feel that my solution is not useful, please unvote it. But, again, I think that this platform is for sharing solution and, just in this case an IMO, this is a simple solution to a simple problem. I don't know that if there are other several good solutions, It might not appear another one. – JonathanLoscalzo Feb 17 '22 at 12:24
  • @JeremyCaney I found some answer similar: [link](https://stackoverflow.com/a/47480453/2946517). Congrats! He is using a regexp in that case, and I'm using `space character` – JonathanLoscalzo Feb 17 '22 at 12:27
  • I don't know why I have the privilege to be lecture by you. Because, it is a simple question that need a simple solution. I don't know why I received this advice and no other people. But thanks anyway – JonathanLoscalzo Feb 18 '22 at 12:20
  • 1
    I had come across your post as part of the “Low Quality Answers” review queue, which is where posts go that are either flagged for not being answers, or which trip certain automated heuristics (e.g., based on length, lack of explanation, &c.). Your answer appears valid, and I did vote to retain it. But I also wanted to be sure you had feedback on how to improve it. It can be overwhelming as a consumer of Stack Overflow to find questions with many code-only answers, so explaining _why_ an approach is different from—if not preferable to—other answers is very useful. – Jeremy Caney Mar 07 '22 at 19:53
-1

In case you want to downsize

# Assuming you are opening a new file
with open(input_file) as file:
    lines = [x for x in reader(file) if x]

# for loop to parse the file by line
for line in lines:
    name = [x.strip().lower() for x in line if x]
    print(name) # Check the result
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fuad Fouad
  • 448
  • 3
  • 9
-2

I really like this answer:

Copy-paste-ready version of @jibberia anwser:

def capitalize(line):
    return ' '.join([s[0].upper() + s[1:] for s in line.split(' ')])

But some of the lines that I was sending split off some blank '' characters that caused errors when trying to do s[1:]. There is probably a better way to do this, but I had to add in a if len(s)>0, as in

return ' '.join([s[0].upper() + s[1:] for s in line.split(' ') if len(s)>0])
Usman Maqbool
  • 3,351
  • 10
  • 31
  • 48
user1475777
  • 92
  • 1
  • 4
  • 2
    This is overly complicated, wth you even go about checking the length?! inefficient. –  Aug 29 '14 at 10:16