LambdaLabTM
Computer Science · Class 11 · Strings Revisited
Programsord & chr⏱️ 15 min read

Case & Kind by Code

Every program on this page has a one-line version using a string method, and every one of them is set in exams anyway — because writing it with ord() and chr() is what proves you know what a character is. Two facts do all the work: the gap of 32, and the fact that each run of codes is unbroken.

1Program 1 — capitals to small letters

📋 The problem

Turn a word of capitals into small letters, without using lower().

to_small.py
# capitals to small letters, using the code numbers instead of lower()

word = 'PYTHON'
small = ''

for ch in word:
    code = ord(ch)
    small = small + chr(code + 32)

print(small)
Output
python
code = ord(ch)

The character's number. Naming it is not required — chr(ord(ch) + 32) is the same thing on one line — but a name makes the next line readable and gives you something to print when it goes wrong.

small = small + chr(code + 32)

Three steps inside out: add 32 to the number, turn the number back into a character, add that character to the collector. The string is still being built the way every string is built.

Watch Out
This program trusts its input, and that is its weakness. Give it 'PY 3' and the space (32) becomes 64, which is '@', and the 3 (51) becomes 83, which is 'S'. No error — just py@S. Adding 32 is only a case conversion for characters that are actually capitals, which is what program 2 fixes.
to_small.py — given 'PY 3' instead of a word of capitals
Output
py@S

2Program 2 — swap the case, checking first

📋 The problem

Swap the case of every letter in a sentence — capitals to small, small to capitals — leaving digits, spaces and punctuation exactly as they are. Use codes only.

swap_by_code.py
# swap the case of every letter, using nothing but codes

sentence = 'LambdaLab CS 11'
swapped = ''

for ch in sentence:
    code = ord(ch)

    if code >= 65 and code <= 90:
        swapped = swapped + chr(code + 32)
    elif code >= 97 and code <= 122:
        swapped = swapped + chr(code - 32)
    else:
        swapped = swapped + ch

print(swapped)
Output
lAMBDAlAB cs 11
Key Takeaway
The range check is isupper(). code >= 65 and code <= 90 asks exactly what ch.isupper() asks, and it is fair only because the capitals are an unbroken run with nothing else inside it. The else is the same else as on the building page: a character that is not being changed still has to be added.

Python allows the shorter spelling 65 <= code <= 90, chaining the two comparisons — but write it out with and until you have met chained comparison properly. Both are correct; only one of them is unambiguous to a reader who has not met the trick.

swap_by_code.py

3Program 3 — what kind of character is this?

📋 The problem

For every character the user types, print the character, its code, and what kind of thing it is — decided by the code alone.

what_kind.py
# what kind of character is it? decided by its code alone

text = input('Enter a few characters: ')

for ch in text:
    code = ord(ch)

    if code >= 48 and code <= 57:
        kind = 'digit'
    elif code >= 65 and code <= 90:
        kind = 'capital letter'
    elif code >= 97 and code <= 122:
        kind = 'small letter'
    elif code == 32:
        kind = 'space'
    else:
        kind = 'something else'

    print(ch, code, kind)
Output
Enter a few characters: Hi 7!
H 72 capital letter
i 105 small letter
  32 space
7 55 digit
! 33 something else

Look at the third line of the output: the character printed is a space, so the line begins with what looks like a gap. That is not a formatting bug — it is what printing a space looks like, and it is exactly why the code is printed beside it.

Key Takeaway
One ladder, one answer per character. The rungs cannot overlap, because a code is in at most one of those runs, so the order of the first four is free here. The else is what makes the program total: every possible character lands somewhere, including the ones nobody thought of.

4Program 4 — turn digit characters into a number

📋 The problem

Add up the digits inside a string using codes rather than int().

digit_sum_by_code.py
# add up the digits of a string, using codes instead of int()

data = 'a1b2c3d4'
total = 0

for ch in data:
    code = ord(ch)

    if code >= 48 and code <= 57:
        total = total + (code - 48)

print('The digits add up to', total)
Output
The digits add up to 10

code - 48 is code - ord('0') written out, and it works for the same reason the case conversion does: the ten digit characters are consecutive, so the distance from '0' is the value. It is what int(ch) does for one digit, done by hand.

Tip
Write ord('0') rather than 48 when you can. Both are right, and total + (code - ord('0')) says how far past zero this digit is, which is the actual idea. A bare 48 in the middle of a program is a number the next reader has to look up.

5Program 5 — count the vowels using codes

📋 The problem

Count the vowels in a sentence without using in and without lower() — codes only.

vowels_by_code.py
# count the vowels, comparing codes rather than characters

sentence = 'Amit Is Learning Python'
count = 0

for ch in sentence:
    code = ord(ch)

    if code >= 65 and code <= 90:
        code = code + 32

    if code == 97 or code == 101 or code == 105 or code == 111 or code == 117:
        count = count + 1

print('Vowels:', count)
Output
Vowels: 7
if code >= 65 and code <= 90:

The lower() step, done to the number: a capital's code is pushed down into the small-letter run so that only five comparisons are needed instead of ten. Note it changes code, not ch — nothing is being printed, so the character itself is not needed.

if code == 97 or code == 101 or ...

The five small vowels: a is 97, e is 101, i is 105, o is 111 and u is 117. Five ors, where ch.lower() in 'aeiou' is one test — which is a fair argument for the method version outside an exam.

Watch Out
Two separate ifs, not if…elif. The second question has to be asked of every character, including the ones the first if has just changed. An elif there would skip the vowel test for every capital, so the capital A and I of this sentence would go uncounted: 5 instead of 7. We ran both. No error, and a perfectly plausible number.

6Recap

+32 lowers, −32 raises

And only for characters that really are letters. Applied blindly, a space becomes @ and a digit becomes a capital.

A range check is the method, spelt out

code >= 65 and code <= 90 is isupper(). It is fair because the run is unbroken — no other character has a code in it.

code − 48 is the digit's value

Better written code − ord('0'). Same idea as the case gap: consecutive codes mean the distance is the answer.

Deal with the characters you are not changing

The else branch that adds ch unchanged is what keeps spaces and punctuation in the result.

✍️ Now write these yourself
  1. 1

    Turn a word of small letters into capitals, using codes and checking first.

    Hint · The 97–122 range, and chr(code - 32). An else for everything else.

  2. 2

    Count the capitals, small letters and digits of a sentence using ranges rather than methods.

    Hint · Three counters and the ladder from program 3, with the printing moved after the loop.

  3. 3

    Print each character of a word with its code, and its code in the other case where there is one.

    Hint · Only letters have another case — everything else prints a dash, or nothing.

  4. 4

    Check whether two words are the same, ignoring case, comparing codes position by position.

    Hint · The index form, and push both codes into one case before comparing them.

  5. 5

    Report the character with the highest code in a sentence.

    Hint · A champion, started at the first character, and ord(ch) > ord(best) inside the loop.

Quick Check

A program adds 32 to the code of every character of 'PY 3'. What comes out?

Quick Check

Why is code >= 65 and code <= 90 a fair test for 'is this a capital?'

Quick Check

In the vowel counter, the two ifs are joined into an if…elif. What happens?