Today, we’ll be looking at how to capitalize a string in Python. There are a few built-in functions for this problem, but we can also roll our own solution.
In short, the capitalize()
method exists for this purpose. That said, if you need something a bit different than what this method provides (e.g. only capitalizing the first letter), then you might need to roll your own solution.
That said, if you’re looking for a bit more of a description, keep reading.
Table of Contents
Video Summary
Like many of the articles in this series, I like to provide a nice video summary for folks who prefer that method of learning. Often the most up to date information can be found in the article, but you’ll still find everything you’ll need in the video above.
Problem Description
When it comes to manipulating strings, a common task that we might want to do is capitalize a string (i.e. convert the first character from lowercase to uppercase). Unfortunately, strings are pretty complex because they can support a huge variety of symbols from letters and numbers to punctuation. Also, let’s not forget that strings can support emojis and characters from languages other than English. Hell, even whitespace has to be encoded somehow.
This complexity brings about a lot of challenges when it comes to string manipulation. As a result, today’s task of capitalization is going to require a few assumptions.
First, when we capitalize a string, we’re only going to concern ourselves with the first character of the string. In other words, we’re not going to try to deal with capitalizing multiple words in a sentence or anything like that.
Second, when we work with strings, the only characters we’re going to concern ourselves with are uppercase and lowercase letters in English. Specifically, these sets of characters:
lowercase = "abcdefghijklmnopqrstuvwxyz" uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
As we’ll see in the solutions below, Python has a function that can perform capitalization for us, but it doesn’t quite adhere to these rules. That said, I’ll share it for the sake of completeness.
Solutions
As always, I like to kick off the list of solutions with a few brute force solutions. Don’t worry! We’ll get to the functions that are already built into Python. Feel free to jump ahead as needed.
Capitalize a String Using ASCII Values
While Python has a capitalize functionality built into the string class, the traditional way to do this would be to leverage the underlying numerical values of each character. If you aren’t already aware, characters are actually integers, and we can access those values using the ord()
function:
>>> ord('s') 115
Now unfortunately, strings are pretty ugly to work with in this state because not every character can be “capitalized.” In other words, what’s the capital version of the number “2” or the symbol “&”?
As a result, there’s a very small range of values we should be concerned about: all the lowercase letters. Fortunately, their numerical values are all adjacent and in alphabetical order:
>>> ord('a') 97 >>> ord('b') 98 >>> ord('y') 121 >>> ord('z') 122
In other words, we can determine if a character is lowercase by checking if its numerical value is between 97 and 122:
if 97 <= ord(character) <= 122: # do something
Then, it’s a matter of mapping the result back to the set of uppercase letters. To do this, we can take advantage of the fact that all of the numerical values of the uppercase letters are also adjacent and in alphabetical order:
>>> ord('A') 65 >>> ord('B') 66 >>> ord('Y') 89 >>> ord('Z') 90 >>> 'a' - 'z'
In this case, the range begins at 65 and ends at 90. As a result, we should be able to subtract the distance between these sets (i.e. 97 – 65 = 32) to map the lowercase letters into the uppercase domain:
if 97 <= ord(character) <= 122: shift = ord(character) - 32
Once we have the character in the proper domain, it’s a matter of using the chr()
function to convert the integer to the appropriate character:
if 97 <= ord(character) <= 122: shift = ord(character) - 32 uppercase = chr(shift)
Now, this will form the core logic of our homemade capitalize function. All that’s left is to extract the first character of the input string, run it through our logic, and return the updated string.
def capitalize(string): character = string[0] if 97 <= ord(character) <= 122: shift = ord(character) - 32 uppercase = chr(shift) return uppercase + string[1:] return string
As we can see, the updated string was constructed from the uppercase character and a slice of the string excluding the first character. If the first character is not a lowercase letter, we return the original string as-is.
Now that we have a capitalize function, here’s what it looks like in action:
>>> capitalize("hello world") 'Hello world' >>> capitalize("Hello world") 'Hello world'
Of course, there are definitely better ways to get this done!
Capitalize a String Using Alphabet Strings
On the off chance that you didn’t know about the numeric values for characters, no worries! There’s another way to roll our own capitalize function. All we have to do is create a pair of strings, one for lowercase letters and another for uppercase letters:
lowercase = "abcdefghijklmnopqrstuvwxyz" uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Now, instead of checking if the first character of the string is in the range of lowercase letters, we can check if it is contained in the lowercase string:
if character in lowercase: # do something
Personally, I like how this reads but to each their own. Anyway, the next step is to map the lowercase character to the uppercase domain. To do that, we need to find the index of the lowercase character in the lowercase string (careful not to get an IndexError):
if character in lowercase: i = lowercase.index(character)
One quick optimization we can make is to use the find()
method instead. That way, we can check if the character is in the set of lowercase characters and get its index at the same time:
i = lowercase.find(character)
If the return value is -1, we know that the letter is not lowercase. In that case, we can return the original string. Otherwise, we can build our capitalized strings.
To do that, we can take the index we got using find()
and plug it into the uppercase string. The result should be the uppercase version of our letter. Then, we rinse and repeat the slice code from above:
i = lowercase.find(character) uppercase[i] + string[1:]
With all the logic out of the way, all that’s left is to put together the function:
def capitalize(string): lowercase = "abcdefghijklmnopqrstuvwxyz" uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" character = string[0] i = lowercase.find(character) return string if i == -1 else uppercase[i] + string[1:]
To limit indentation, we use a ternary operator in the return statement. That said, it’s perfectly acceptable to explicitly write out the if statements.
Regardless, here’s what this function looks like in action:
>>> capitalize("hello world") 'Hello world' >>> capitalize("Hello world") 'Hello world'
Again, this isn’t the best way to go about capitalizing a string. That said, if you needed to roll your own string manipulation function, both of the functions up to this point might serve as a good start.
Capitalize a String Using Built-in Upper Method
In Python, there are two core capitalization methods: upper()
and capitalize()
. Neither of these methods really gives us the simplified behavior provided in the problem description, but the upper()
method can be used to give us what we want.
Typically, the upper()
method is used to uppercase every character in a string:
>>> string = "how now brown cow" >>> string.upper() 'HOW NOW BROWN COW'
That said, it’s pretty easy to use the same style of slice code from before to implement a capitalize function:
def capitalize(string): character = string[0] return character.upper() + string[1:]
In other words, we can grab the first character, call upper()
on it, and concatenate it with the rest of the original string. In this case, upper()
is basically providing all of the lowercase checking logic from our previous solutions—albeit in a more sophisticated way to handle all cased characters.
Naturally, here’s what that looks like in action:
>>> capitalize("hello world") 'Hello world' >>> capitalize("Hello world") 'Hello world'
Up next, we’ll take a look at the capitalize()
method.
Capitalize a String Using Built-in Capitalize Method
Finally, Python comes equipped with the capitalize()
method right out of the box. Unfortunately, it doesn’t quite adhere to our requirements because it does a bit more than just capitalize the first character of a string. In addition, it converts all other characters to lowercase. Likewise, it likely handles characters beyond the set we’ve defined. That said, I figured I’d share it for completeness.
Since the capitalize()
method works out of the box, there’s not much we need to do but call it. Of course, since it’s a method, it works a bit differently than the functions we’ve defined above. In particular, this method has to be called on an existing instance of a string:
>>> "hello world".capitalize() 'Hello world' >>> "Hello world".capitalize() 'Hello world'
Also, it’s probably worth demonstrating a string or two with capital letters throughout:
>>> "Hello WoRlD".capitalize() 'Hello world'
Notice how the capitalize method takes care of characters that are capitalized throughout. This is not the behavior of the functions we created previously. That said, if you don’t mind, this is probably the method for you.
Performance
With the solutions out of the way, let’s talk performance. In my experience, the methods provided by Python are almost always significantly faster than anything we can write ourselves. That said, it’s worth taking a look at how our custom solutions fair.
To do that, we’ll be using the timeit
package. If you want to learn more about this package and how it’s used, check out my article on performance testing. Otherwise, let’s start by storing our solutions in strings.
setup = """ input = "test string" def capitalize_ascii(string): character = string[0] if 97 <= ord(character) <= 122: shift = ord(character) - 32 uppercase = chr(shift) return uppercase + string[1:] return string def capitalize_alphabet(string): lowercase = "abcdefghijklmnopqrstuvwxyz" uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" character = string[0] i = lowercase.find(character) return string if i == -1 else uppercase[i] + string[1:] def capitalize_upper(string): character = string[0] return character.upper() + string[1:] """ capitalize_by_hand = """ captalize_ascii(input) """ capitalize_by_mapping = """ capitalize_alphabet(input) """ capitalize_with_upper = """ capitalize_upper(input) """ capitalize = """ input.capitalize() """
Alright, that was a bit long, but we’re now ready to begin testing. Here’s what that looks like:
>>> import timeit >>> min(timeit.repeat(setup=setup, stmt=capitalize_by_hand)) 0.30442010000001574 >>> min(timeit.repeat(setup=setup, stmt=capitalize_by_mapping)) 0.34245180000004893 >>> min(timeit.repeat(setup=setup, stmt=capitalize_with_upper)) 0.21950409999999465 >>> min(timeit.repeat(setup=setup, stmt=capitalize)) 0.11746000000005097
For the sake of completeness, I like to run these sort of tests with larger strings despite all of our solutions running in constant time. In this case, I updated input as follows:
input = "abc" * 100
Despite our solutions running in constant time, the built-in capitalize()
certainly does not. Here’s the consequence:
>>> min(timeit.repeat(setup=setup, stmt=capitalize_by_hand)) 0.33476870000004055 >>> min(timeit.repeat(setup=setup, stmt=capitalize_by_mapping)) 0.36098470000001726 >>> >>> min(timeit.repeat(setup=setup, stmt=capitalize_with_upper)) 0.2651783000000023 >>> min(timeit.repeat(setup=setup, stmt=capitalize)) 1.7041871000000128
Despite how much faster the built-in method is for small strings, it doesn’t scale too well. Of course, that makes sense, right? It’s changing all the characters in the string, so it probably runs in linear time. In general, however, all solutions seem to be pretty fast, so take your pick!
More recently, I’ve been visualizing the testing you’ve seen above through the How to Python repo. Here’s the same sort of findings visualized:
With that said, let’s move on to the challenge.
Challenge
For today’s challenge, I had a really fun idea that I might turn into a series. Given how different the capitalize()
method is from our solutions, I wonder how hard it would be to duplicate some of the behavior. For example, could you write your own version of the capitalize method that follows the method description?
Return a copy of the string with its first character capitalized and the rest lowercased.
Source: Python Documentation
As always, I’ll kick things off with a solution of my own:
If you’d like to share a solution, feel free to use #RenegadePython on Twitter, and I’ll give it a share!
A Little Recap
Welp, that’s it for today! As always, here’s the list of solutions in one convenient place:
# A capitalize function leveraging character values def capitalize_ascii(string): character = string[0] if 97 <= ord(character) <= 122: shift = ord(character) - 32 uppercase = chr(shift) return uppercase + string[1:] return string # A capitalize function leveraging alphabet strings def capitalize_alphabet(string): lowercase = "abcdefghijklmnopqrstuvwxyz" uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" character = string[0] i = lowercase.find(character) return string if i == -1 else uppercase[i] + string[1:] # A capitalize function leveraging the upper method def capitalize_upper(string): character = string[0] return character.upper() + string[1:] # The built-in capitalize method str.capitalize()
Otherwise, thanks again for checking out the site. If you’d like to become part of the community, check out my list of ways to grow the site. There you’ll find links to Patreon and Discord.
In addition, you can support the site by checking out these related articles:
- How to Convert an Integer to a String in Python: Type Casting and f-Strings
- How to Convert a String to Lowercase in Python: lower() and More
Likewise, here are a few python resources from the folks at Amazon (#ad):
- Effective Python: 90 Specific Ways to Write Better Python
- Python Tricks: A Buffet of Awesome Python Features
- Python Programming: An Introduction to Computer Science
Once again, thanks for stopping by. I hope this article was helpful!
Recent Code Posts
Unpacking the Jargon Around Compilers, Interpreters, and More
Today, we're going to get a little pedantic and try to define concepts like compiler and interpreter. Of course, I ultimately don't think it matters what the exact definitions are for practical...
Generally, people think of Python as a messy language because it lacks explicit typing and static type checking. But, that's not quite true in modern times. Surely, we can take advantage of type...