Strings
- Module
- M1.7
- Lesson
- 1 of 1
- Reading time
- 4 min
In this lesson
- Find how many characters a string holds with
len(). - Read one character with indexing (
word[i]), including from the end with a negative index. - Take out part of a string with slicing (
word[a:b]). - Convert between a character and its code point with
ord()andchr().
Every string so far has been read, printed, or compared as one whole piece of text. Many CCC problems need to look inside a string instead: one character at a time, a range of characters, or a count of how many it holds. This lesson covers reading a string's length, picking out characters and ranges of characters, and moving between a character and the number that represents it.
Finding a string's length with len()
len() takes a string and returns how many characters it holds.
word = input()print(len(word))Input
pumpkinOutput
7"pumpkin" holds seven characters, so len(word) is 7. len() works on other kinds of values too, covered as they come up; here it counts characters.
A blank line, read with input(), still has a length: 0, since it holds no characters at all. Checking len(word) == 0 is a common way to notice that a line was empty, rather than comparing it against the literal text "" directly.
Reading one character with indexing
Indexing reads a single character out of a string by its position, written word[i]. Positions start at 0, the same way range() does, so the first character is word[0], not word[1].
word = input()print(word[0])print(word[-1])Input
pumpkinOutput
p
nword[0] is "p", the first character. word[-1] is "n", the last one: a negative index counts backward from the end, so -1 always means the last character, however long the string is, without needing len(word) - 1.
word = input()print(word[10])Input
catError: IndexError
Traceback (most recent call last):
File "index_error.py", line 2, in <module>
print(word[10])
IndexError: string index out of range"cat" only has characters at indices 0, 1 and 2. Asking for word[10] reaches past the end, so Python raises an IndexError instead of returning something meaningless. Whenever you index with a value you computed, check that it can never reach past the last valid index, len(word) - 1.
Negative indices have their own valid range too. word[-1] is the last character, and word[-len(word)] is the first. An index further back than that, such as word[-100] on a three-letter word, raises the same IndexError. Whichever direction you count from, the index has to land on a character the string actually holds.
Taking out a range with slicing
Slicing reads out a whole range of characters at once, written word[a:b]. Like range(a, b), it starts at a and stops just before b, never including the character at b itself.
word = input()print(word[1:4])print(word[:3])print(word[3:])Input
elephantOutput
lep
ele
phant"elephant" sliced [1:4] gives "lep": characters at indices 1, 2 and 3. Leaving out the start, [:3], begins from 0, giving "ele". Leaving out the stop, [3:], runs to the end of the string, giving "phant".
word = input()print(word[2:100])Input
catOutput
t"cat" sliced [2:100] gives "t", just the characters that actually exist from index 2 onward. Unlike indexing, a slice never raises an error for a range that reaches past the end. It simply stops at whatever characters the string actually has.
word[:], with both sides left out, copies the whole string. It rarely does anything useful on its own. The same pattern with only one side left out, word[a:] or word[:b], comes up far more often: everything from a chosen point onward, or everything up to it.
Converting between a character and its code point
Every character Python can store has a whole number behind it, called its code point. ord() gives the code point of a single character. It only ever accepts one character at a time, never a whole word. chr() goes the other way, turning a code point back into its character.
print(ord("a"))print(chr(97))print(chr(ord("a") + 1))Output
97
a
bord("a") is 97, the code point of a lowercase a. chr(97) reverses that, giving back "a". Adding 1 to ord("a") and converting back with chr() gives "b", the next letter in the alphabet: ord() and chr() together let you step through letters by their position, not just by typing each one out.
Uppercase letters have their own, separate codes: ord("A") is 65, a different number from ord("a"). A problem that shifts letters by some number of positions, wrapping from "z" back to "a", needs % alongside ord() and chr(). That keeps the result inside the alphabet's own range of code points, rather than sliding past it into an unrelated character.
A pattern to avoid: building a string with +=
word = input()result = ""for ch in word: result += chprint(result)Input
catOutput
catThis copies word into result one character at a time, and the output is correct. On PyPy, though, growing a string this way, character by character, gets slower the longer the string is, since each += builds an entirely new string. The module on lists shows the fast way to build up a result piece by piece; for now, know that this pattern is worth avoiding once a string gets long.
Tracing a character loop
(nothing printed yet)- Just changed
Figure 1Looping over every index of a word, pairing each one with its character
Read the steps as text
The program loops over every index of a word, printing each index next to the character at that position.
A three-letter word
- Python starts at the top of the file. Line 1 runs first.
- Line 1 runs:
wordis created with the value'cat'. - Line 2 runs: the loop gives
iits first value,0.range(len(word))visits every valid index ofword, from0up to the last one. - Line 3 runs: it prints
0 c.word[i]reads the single character at indexi, the same character this pass's index refers to. - Line 2 runs: the loop gives
iits next value,1. - Line 3 runs: it prints
1 a. - Line 2 runs: the loop gives
iits next value,2. - Line 3 runs: it prints
2 t. - The program has finished: no lines are left to run.
A four-letter word
- Python starts at the top of the file. Line 1 runs first.
- Line 1 runs:
wordis created with the value'frog'. - Line 2 runs: the loop gives
iits first value,0.range(len(word))visits every valid index ofword, from0up to the last one. - Line 3 runs: it prints
0 f.word[i]reads the single character at indexi, the same character this pass's index refers to. - Line 2 runs: the loop gives
iits next value,1. - Line 3 runs: it prints
1 r. - Line 2 runs: the loop gives
iits next value,2. - Line 3 runs: it prints
2 o. - Line 2 runs: the loop gives
iits next value,3. - Line 3 runs: it prints
3 g. - The program has finished: no lines are left to run.
range(len(word)) visits every valid index of word, whatever its length, and word[i] reads the character at each one in turn. The three-letter preset loops three times; the four-letter preset loops four, since len(word) itself decides how many indices there are to visit.
Recap
This lesson covered finding a string's length with len(), and reading one character with indexing and a negative index from the end. It also covered taking out a range with slicing, and converting between a character and its code point with ord() and chr(). Last, it covered the IndexError an out-of-range index raises, and a pattern to avoid when building up a string in a loop. The three problems below all work with a line of text one character at a time.
Practice
Try these on the judge. Each link opens the problem on DMOJ.
- 2015 J2Happy or Sad (opens on DMOJ in a new tab) DMOJ
Count two kinds of faces in a line of text and decide whether it reads happy, sad, unsure, or neither.
Why DMOJ: Tries the same kind of problem on DMOJ, which holds 2014 to 2020.
- 2019 J2Time to Decompress (opens on DMOJ in a new tab) DMOJ
Turn each "count and character" line into that character repeated that many times.
Why DMOJ: Tries the same kind of problem on DMOJ, which holds 2014 to 2020.
- 2018 J2Occupy parking (opens on DMOJ in a new tab) DMOJ
Compare two lines and count where both mark the same spot.
Why DMOJ: Tries the same kind of problem on DMOJ, which holds 2014 to 2020.