Skip to content
CCC Python Course

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() and chr().

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.

examples/string_length.py
word = input()print(len(word))

Input

pumpkin

Output

7
Counting the characters in a word

"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].

examples/first_and_last.py
word = input()print(word[0])print(word[-1])

Input

pumpkin

Output

p
n
The first and last characters of a word

word[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.

examples/index_error.py
word = input()print(word[10])

Input

cat

Error: IndexError

Traceback (most recent call last):
  File "index_error.py", line 2, in <module>
    print(word[10])
IndexError: string index out of range
Indexing past the end of a three-letter word

"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.

examples/slice_basics.py
word = input()print(word[1:4])print(word[:3])print(word[3:])

Input

elephant

Output

lep
ele
phant
Slicing three different ranges from one word

"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".

examples/slice_out_of_range.py
word = input()print(word[2:100])

Input

cat

Output

t
A slice past the end of a string, with no error

"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.

examples/ord_chr_basics.py
print(ord("a"))print(chr(97))print(chr(ord("a") + 1))

Output

97
a
b
Moving between a letter and its code point

ord("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 +=

examples/slow_concat.py
word = input()result = ""for ch in word:    result += chprint(result)

Input

cat

Output

cat
Building a string one character at a time with +=

This 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

Input
1word = input()
2for i in range(len(word)):
3 print(i, word[i])
Output so far
(nothing printed yet)
Frames and objects, step 1 of 9FramesGlobal frame
Speed
Python starts at the top of the file. Line 1 runs first.
  • 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

  1. Python starts at the top of the file. Line 1 runs first.
  2. Line 1 runs: word is created with the value 'cat'.
  3. Line 2 runs: the loop gives i its first value, 0. range(len(word)) visits every valid index of word, from 0 up to the last one.
  4. Line 3 runs: it prints 0 c. word[i] reads the single character at index i, the same character this pass's index refers to.
  5. Line 2 runs: the loop gives i its next value, 1.
  6. Line 3 runs: it prints 1 a.
  7. Line 2 runs: the loop gives i its next value, 2.
  8. Line 3 runs: it prints 2 t.
  9. The program has finished: no lines are left to run.

A four-letter word

  1. Python starts at the top of the file. Line 1 runs first.
  2. Line 1 runs: word is created with the value 'frog'.
  3. Line 2 runs: the loop gives i its first value, 0. range(len(word)) visits every valid index of word, from 0 up to the last one.
  4. Line 3 runs: it prints 0 f. word[i] reads the single character at index i, the same character this pass's index refers to.
  5. Line 2 runs: the loop gives i its next value, 1.
  6. Line 3 runs: it prints 1 r.
  7. Line 2 runs: the loop gives i its next value, 2.
  8. Line 3 runs: it prints 2 o.
  9. Line 2 runs: the loop gives i its next value, 3.
  10. Line 3 runs: it prints 3 g.
  11. 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.

  1. 2015 J2
    Happy 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.

  2. 2019 J2
    Time 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.

  3. 2018 J2
    Occupy 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.