Character codes and conversion
ord and chr, ASCII, comparing strings, and a Caesar cipher.
Do this lesson in the simulatorA 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))
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))
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")
"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())
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)
% 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
- Print the whole alphabet with one loop and
chr, without typing any letters. - Make the cipher keep spaces as they are, so that
HELLO ROBOTworks. - Play a note for each letter of a name:
tone(ord(letter) * 5, 0.2). Which name sounds best?