All 2.2 24 min read 10 question quiz 18 exam marks

String Manipulation

Indexing, slicing, the string methods you will actually use, and why text.upper() appears to do nothing at all.

Indexing and slicing

A string is a sequence of characters, and every character has a position, counting from zero.

Python
word = "Computing"
#       012345678
print(word[0])        # C
print(word[3])        # p
print(word[-1])       # g, the last character
print(word[-2])       # n, the second from last
print(len(word))      # 9
The last index is len(word) - 1

word[9] on a nine character string raises an IndexError, because the positions run 0 to 8. Negative indexing with word[-1] is the safe way to reach the end.

Slicing

A slice takes a section of the string, using [start:end]. The start is included and the end is excluded.

Python
word = "Computing"

print(word[0:4])      # Comp
print(word[4:])       # uting, from 4 to the end
print(word[:4])       # Comp, from the start to 4
print(word[:])        # Computing, the whole thing
print(word[::-1])     # gnitupmoC, reversed
print(word[0:9:2])    # Cmuig, every second character
Why the end is excluded

It means word[:4] and word[4:] fit together perfectly with no overlap and nothing missing. The length of word[a:b] is always b - a, which is far easier to reason about than it first looks.

Looping through a string

Python
for letter in "Python":
    print(letter)

You rarely need the index. If you do want both the position and the character, use enumerate:

Python
for i, letter in enumerate("Python"):
    print(i, letter)
A string is a row of characters, each with an indexThe word Computer drawn as eight letter tiles. Above each tile is its index, counting from 0 at the first letter to 7 at the last, and below it is the negative index, counting back from the end, from minus 8 to minus 1. A slice takes part of the string: word, bracket, 0, colon, 3 gives Com, which runs from index 0 up to but not including index 3, and word, bracket, 3, colon gives puter, from index 3 to the end. word minus one is the last character, r. Below, four things you can do with a string: len gives the number of characters, which is 8; upper gives a new string in capitals; find gives the index of the first match, here 3 for the letter p; and a plus sign joins two strings together. A string is never changed in place: each of these gives back a new string.indexfrom the endC0-8o1-7m2-6p3-5u4-4t5-3e6-2r7-1word[0:3] = "Com"word[3:] = "puter"word[-1] = "r"123len(word)8how many charactersword.upper()"COMPUTER"a new string in capitalsword.find("p")3index of the first matchword + "s""Computers"+ joins two strings4
  1. Every character has an index. The first is 0, and negative indexes count back from the end.
  2. A slice [a:b] runs from index a up to, but not including, b. Leave b out to go to the end.
  3. [-1] is the last character.
  4. Functions and methods build and search strings, and each one gives back a new string.
In exam pseudocode the same idea is written as substring: check your board's command set for the exact form.

String methods

Python
text = "  Hello World  "

print(text.strip())            # "Hello World", removes surrounding spaces
print(text.upper())            # "  HELLO WORLD  "
print(text.lower())            # "  hello world  "
print(text.title())            # capitalises each word
print(text.replace("l", "L"))  # swaps every match
print(text.strip().split(" ")) # ["Hello", "World"]
print("-".join(["a", "b", "c"]))  # "a-b-c"
print(text.count("l"))         # 3
print(text.find("World"))      # 8, the position, or -1 if not found
print("Hello" in text)         # True
Strings cannot be changed in place

text.upper() does not change text. It returns a brand new string and leaves the original exactly as it was. You must write text = text.upper() to keep the result. This single misunderstanding causes more confusion than any other string bug.

Python
name = "aisha"
name.title()          # returns "Aisha", but throws it away
print(name)           # aisha, unchanged

name = name.title()   # this is what you meant
print(name)           # Aisha

split and join are opposites

Python
line = "Aisha,Ben,Chloe"
names = line.split(",")        # ["Aisha", "Ben", "Chloe"]
back = ",".join(names)         # "Aisha,Ben,Chloe"

split turns one string into a list. join turns a list back into one string. Note that join is called on the separator, not on the list, which catches everybody out once.

Case insensitive comparison

Python
reply = input("Continue? ")

if reply.lower() == "yes":     # accepts Yes, YES, yes, yEs
    print("Carrying on")

Converting both sides to the same case before comparing is the standard way to stop a capital letter breaking a comparison.

Six string methods applied to the text with spaces round Hello World, and why the original never changesSix string methods applied to text equal to two spaces, Hello World, two spaces. upper gives all capitals. strip removes the spaces at the ends, giving Hello World. replace of l with capital L swaps every match, giving HeLLo WorLd with its spaces. strip then split on a space breaks the text into the list Hello, World. join of the list a, b, c with a hyphen builds the text a-b-c. find of World gives 8, the position where it starts. On the right a reminder that strings do not change: text dot upper makes a brand new string and leaves text as it was, so to keep the result you assign it, name equals name dot upper. Split and join are opposites.text = "  Hello World  "1text.upper()"  HELLO WORLD  "2text.strip()"Hello World"3text.replace("l", "L")"  HeLLo WorLd  "4text.strip().split(" ")["Hello", "World"]5"-".join(["a", "b", "c"])"a-b-c"6text.find("World")8Strings are fixed7textstays the sametext.upper() makesa brand new stringnew stringkeep it by assigning:name = name.upper()split and join are opposites: split breaks text into a list, join builds text from a list.
  1. upper() makes every letter a capital.
  2. strip() removes spaces from both ends.
  3. replace() swaps every match for something else.
  4. split() breaks a string into a list.
  5. join() builds a string from a list.
  6. find() gives the position of the first match, or -1 if there is none.
  7. A method returns a new string. The original is never changed unless you assign the result.
Methods return new strings. To keep the result, assign it to a variable.

Validating and building text

Checking what a string contains

Python
"42".isdigit()      # True
"abc".isalpha()     # True
"abc123".isalnum()  # True
" ".isspace()       # True
"".isdigit()        # False, an empty string is never valid

isdigit() is the standard way to check that input can safely be converted with int():

Python
reply = input("Enter a number: ")

if reply.isdigit():
    number = int(reply)
    print(f"Twice that is {number * 2}")
else:
    print("That was not a whole number.")

f-strings

The clearest way to build text that contains values.

Python
name = "Aisha"
score = 92

print(f"{name} scored {score} out of 100")
print(f"Rounded: {3.14159:.2f}")           # 3.14
print(f"As a percentage: {score / 100:.1%}")  # 92.0%
print(f"Padded: {name:>10}")               # right aligned in 10 characters
Use f-strings for every piece of mixed output

Building output with + and str() is longer, easier to get wrong, and crashes the moment you forget a conversion. An f-string handles the conversion for you and reads in the order the sentence is spoken.

Two classic string problems

Counting vowels:

Python
word = input("Enter a word: ").lower()
vowels = 0

for letter in word:
    if letter in "aeiou":
        vowels += 1

print(f"{word} contains {vowels} vowels")

Checking a palindrome:

Python
phrase = input("Enter a phrase: ").lower().replace(" ", "")

if phrase == phrase[::-1]:
    print("That is a palindrome")
else:
    print("That is not a palindrome")

Both rely on normalising the text first, lowering the case and removing anything that should not count, so the comparison is fair.

Key terms you must be able to define

String
A sequence of characters, written inside quotation marks.
Index
The position of a character in a string, counting from 0.
Slice
A section of a string, taken with a start and an end index.
Immutable
Cannot be changed after creation. Strings in Python are immutable.
Concatenation
Joining two strings end to end with the + operator.
split
A string method that breaks text into a list at a chosen separator.
join
A string method, called on the separator, that combines a list of strings into one.
f-string
A string beginning with f where values written in braces are inserted directly.
isdigit
A string method returning True only when every character is a digit.

Flashcards

Say the definition out loud before you flip the card. Retrieving it from memory is what builds recall, reading it again is not.

DefineString
AnswerA sequence of characters, written inside quotation marks.
DefineIndex
AnswerThe position of a character in a string, counting from 0.
DefineSlice
AnswerA section of a string, taken with a start and an end index.
DefineImmutable
AnswerCannot be changed after creation. Strings in Python are immutable.
DefineConcatenation
AnswerJoining two strings end to end with the + operator.
Definesplit
AnswerA string method that breaks text into a list at a chosen separator.
Definejoin
AnswerA string method, called on the separator, that combines a list of strings into one.
Definef-string
AnswerA string beginning with f where values written in braces are inserted directly.

Reach the top grade on this topic

  • Use negative indexes and slices confidently, including the reversing slice [::-1]
  • Remember that every string method returns a new string rather than changing the original
  • Use split and join to move between a line of text and a list of values
  • Validate text with isdigit before converting it, rather than letting int() crash
  • Use f-strings, with formatting such as :.2f, for all output that mixes text and values

Mistakes that cost marks here

Avoid these
  • Writing text.upper() and expecting text to change. The result must be assigned.
  • Using an index equal to the length of the string, which is out of range.
  • Forgetting that a slice excludes its end index.
  • Calling join on the list instead of on the separator.
  • Comparing input to "yes" without lowering the case first, so "Yes" fails.
  • Building output with lots of + and str() instead of an f-string.
Fun fact

Strings in Python cannot be changed once created. Every method that looks like it edits a string actually builds a brand new one and hands it back, which is exactly why you must assign the result to something.

Knowledge check

0 of 10 answered
1What does "Computing"[0:4] give?
2What does text.upper() do to the variable text?
3What does word[::-1] give?
4What does "a,b,c".split(",") produce?
5Which method checks that a string contains only digits?
6What does f"Score: {points}" do?
7What does "Computing"[-1] give?
8How is join called?
9What does "Hello".find("z") return?
10Why compare reply.lower() == "yes" rather than reply == "yes"?
Score 0 / 10

Exam-style questions

Five written questions in the style of the real paper. Write a full answer, then let the marker check it against the mark scheme.

18 marks
1State what is meant by saying that strings in Python are immutable.2 marks
State

Mark scheme0 / 2
  • LA string cannot be changed after it is created
  • LMethods return a new string rather than altering the original
Model answer

Immutable means that once a string has been created its contents cannot be altered. Methods such as upper, replace and strip do not change the original string at all: they build and return a brand new string, which is why the result must be assigned to a variable if it is to be kept.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
2Write a program that counts how many vowels are in a word entered by the user.4 marks
Write

Mark scheme0 / 4
  • LReads the word and converts it to lower case
  • LInitialises a counter to zero
  • LLoops through each character in the word
  • LIncreases the counter when the character is a vowel and prints the total
Model answer

word = input("Enter a word: ").lower() vowels = 0 for letter in word: if letter in "aeiou": vowels += 1 print(f"{word} contains {vowels} vowels") Converting the input to lower case means capital letters are counted too. The loop walks through the string one character at a time, and the in operator checks whether the current character appears in the string of vowels, which is much shorter than writing five separate comparisons.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
3Explain why name.title() on its own appears to have no effect, and state the correction.3 marks
Explain

Mark scheme0 / 3
  • LStrings are immutable so the original cannot be changed
  • LThe method builds and returns a new string
  • LThe returned value must be assigned, as in name = name.title()
Model answer

Strings in Python are immutable, so no method is able to alter the string it is called on. The title method builds a brand new string with each word capitalised and returns it, leaving the original completely untouched. Written on a line by itself the returned string is simply discarded, so the variable appears unchanged. The correction is to assign the result back, writing name = name.title(), which makes the name refer to the new string instead.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
4Write a program that reads a line of text containing names separated by commas and prints each name on its own line, numbered.5 marks
Write

Mark scheme0 / 5
  • LReads the line of input
  • LSplits it on commas into a list
  • LLoops through the resulting list
  • LRemoves surrounding spaces from each name
  • LPrints each name with a number
Model answer

line = input("Enter names separated by commas: ") names = line.split(",") for i, name in enumerate(names, start=1): print(f"{i}. {name.strip()}") The split method breaks the line into a list at every comma. Because the user is likely to type a space after each comma, strip is used to remove any surrounding whitespace from each name before it is printed. Using enumerate with start set to 1 gives a counter beginning at 1 rather than 0, which is more natural for a numbered list shown to a user.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
5Explain how a program can check whether a phrase is a palindrome, ignoring spaces and capital letters.4 marks
Explain

Mark scheme0 / 4
  • LConvert the phrase to a single case
  • LRemove the spaces
  • LReverse the phrase using a slice with a step of -1
  • LCompare the normalised phrase with its reverse
Model answer

The phrase must first be normalised so that differences which should not count are removed. Converting it entirely to lower case means a capital letter at the start does not cause a mismatch, and replacing every space with nothing means the spacing of the original phrase is ignored. The normalised phrase is then reversed using the slice [::-1], which walks through the characters with a step of minus one. If the normalised phrase and its reverse are equal then the phrase reads the same in both directions and is a palindrome. Without normalising first, a genuine palindrome such as Never odd or even would be reported as not being one.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
Machine mark 0 / 18