Character codes and conversion

ord and chr, ASCII, comparing strings, and a Caesar cipher.

F3.2Strings, lists and recordsGCSE15 min

Do this lesson in the simulator

A computer stores only numbers. Every character you type, from A to ? to a space, is stored as a number called its character code. This lesson shows the codes, how to convert between characters and codes, and a secret message that works because letters are numbers.

ord and chr

ord gives the code for a character. chr gives the character for a code:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

print(ord("A"), ord("B"), ord("Z"))
print(ord("a"), ord("z"))
print(ord("0"), ord(" "))
print(chr(66), chr(111), chr(116))

Run this in the simulator

A is 65, B is 66, and the alphabet counts up from there, so Z is 90. Lower-case letters start at 97. The digit 0 is 48, and even a space has a code, 32. These are the codes of ASCII, the character set that the first 128 codes of Unicode still follow.

Letters are in order

Because the codes count up, you can do arithmetic on letters:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

letter = "C"
print("the next letter is", chr(ord(letter) + 1))
print("C is letter number", ord(letter) - ord("A") + 1, "of the alphabet")
print("upper to lower:", chr(ord(letter) + 32))

Run this in the simulator

Lower case is always 32 codes after upper case, which is all that lower() does under the hood.

Comparing strings

Comparing strings with < and > compares their codes, one character at a time:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

print("apple" < "banana")
print("Zebra" < "apple")
print("robot" == "Robot")

Run this in the simulator

"Zebra" < "apple" is True, because Z (90) comes before a (97). Capital letters sort before lower case. Convert both strings with lower() before comparing if case should not matter.

Turning digits into numbers, and back

int() and str() from lesson F1.8 convert whole strings. Under the hood, a digit is a character code too:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

reading = "42"
print(int(reading) + 1)                  # the whole string as a number
print(ord(reading[0]) - ord("0"))        # the first digit, worked out from its code
print(str(99) + " red balloons")
print(reading.isdigit(), "4two".isdigit())

Run this in the simulator

isdigit() asks whether every character is a digit, which lets a program check an answer before it calls int() and crashes.

A secret message

A Caesar cipher moves every letter a fixed number of places along the alphabet. With character codes it is a loop:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

message = "ROBOT"
shift = 3
secret = ""
for letter in message:
    code = ord(letter) - ord("A")          # 0 to 25
    code = (code + shift) % 26             # move along, wrapping Z round to A
    secret = secret + chr(code + ord("A"))
print(secret)

Run this in the simulator

% 26 wraps the end of the alphabet round to the start, so X shifted by 3 is A. Change shift to -3 and put the secret back in message: it decodes.

Task: shift the letters

Ask Message? and print the message with every letter moved one place along the alphabet. The task answers HAL (the computer in a famous film), and the answer is the name of a famous computer company. The message will be capital letters only. Work it out with ord and chr.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

message = input("Message? ")
secret = ""

Challenges

  1. Print the whole alphabet with one loop and chr, without typing any letters.
  2. Make the cipher keep spaces as they are, so that HELLO ROBOT works.
  3. Play a note for each letter of a name: tone(ord(letter) * 5, 0.2). Which name sounds best?