Week 11 — Lecture Outline · Strings in Depth & Text Processing
Course: Introduction to Computer Science — CS1 / Programming Fundamentals in Python (CSCI 1101) · Silver Oak University (fictional sample) · Prof. Okafor
Objective covered: Objective 7 — Process text with Python: use the core string methods, explain why strings are immutable (methods return a new string), and write simple text algorithms.
SLOs touched: A (write and run a correct text-processing program) · B (trace method results and predict output; find and fix the immutability bug)
Meeting pattern: 2 studio sessions × 75 min = 150 min. Segment minutes below total ~150; scale to your own pattern.
Every method result, traced value, and program output in this outline was produced by actually running the code in Python — not hand-traced. Run them live in class; the outputs are exact.
Week at a Glance
| The week's big question | "How do I take a piece of text apart, clean it up, search it, and rebuild it — without accidentally expecting the original to change?" |
| By the end of the week, students can… | (1) call the core string methods — .upper(), .lower(), .strip(), .split(), .join(), .replace(), .find(), .count(), .startswith() — and predict what each returns; (2) explain immutability — a method returns a new string and leaves the original alone, so you must reassign; (3) write a simple text algorithm (count words, count a character, find/replace, reverse with s[::-1]) and run it to confirm; (4) catch the immutability bug — code that calls a method but forgets to reassign. |
| Key vocabulary | string, method, immutable / immutability, .upper(), .lower(), .strip(), .split(), .join(), .replace(), .find(), .count(), .startswith(), substring, token / word, list (from .split()), separator / delimiter, reassign, slice s[::-1], text algorithm, normalize |
| Materials | slides (Deck 11), the week's readings + video links, a free online Python environment + Python Tutor (links in the readings), one approved chatbot (Gemini / Claude / ChatGPT) for the AI-critique moment and the tutorial |
| Timing note | 8 segments, ~150 min total. Session 1 = Segments 1–4 (~75). Session 2 = Segments 5–8 (~75). This is a studio: code along on the projector and have students type every method call into the online environment with you — strings are where running-it-yourself pays off most. |
Segment 1 — Hook & the Promise (8 min) · Session 1 opens
Hook. Put a messy line of text on the slide exactly as a user might type it: " Hello, WORLD! " — leading spaces, trailing spaces, shouting capitals. Ask the room: "A form just handed your program this. What has to happen before you can store it, compare it, or search it?" They'll say things like "trim the spaces," "make the capitals normal." Good — those are string methods, and by the end of today you'll clean this exact string down to hello, world! in one line.
The promise (write it on the board): "By Friday you'll take text apart, search it, and rebuild it with the core string methods — and you'll understand the one gotcha that fools everyone: a string method never changes the original; it returns a new one."
Why it matters line (memory hook): "String methods return a new string — they never change the original."
Segment 2 — The Core String Methods (22 min)
Plain language first. A string method is a built-in action you ask a string to perform, written with a dot: text.upper(). You've used len(text) (a function) and indexing text[0] since Week 3; methods are the third tool, and there's a method for almost every text job.
Code-along — run each one, read the result (everyone types along):
Case + whitespace:
print("hello".upper()) # HELLO
print("HELLO".lower()) # hello
print(" hi ".strip()) # hi (the spaces are gone)
Run-verified outputs: HELLO, hello, and hi (with the surrounding spaces removed — .strip() trims whitespace off both ends).
Searching + counting:
print("hello".find("l")) # 2
print("hello".find("z")) # -1
print("banana".count("a")) # 3
print("hello".startswith("he")) # True
Run-verified: .find("l") is 2 (the index of the first match, counting from 0), .find("z") is -1 (a sentinel meaning not found — note it returns a position, not True/False), .count("a") is 3, and .startswith("he") is True.
Replacing:
print("banana".replace("a", "o")) # bonono
print("I love cats".replace("cats", "dogs")) # I love dogs
Run-verified: bonono (every a becomes o — .replace replaces all matches, not just the first) and I love dogs.
Land it on a slide (a methods table students copy):
| Method | What it does | Example → run-verified result |
|---|---|---|
.upper() / .lower() |
change case | "hi".upper() → HI |
.strip() |
trim whitespace off both ends | " hi ".strip() → hi |
.replace(a, b) |
replace all a with b |
"aaa".replace("a","b") → bbb |
.find(x) |
index of first x, or -1 if absent |
"hello".find("z") → -1 |
.count(x) |
how many times x appears |
"banana".count("a") → 3 |
.startswith(x) |
True if the string starts with x |
"hello".startswith("he") → True |
Segment 3 — .split() and .join(): String ↔ List (the code-along) (24 min)
Set it up: "Two methods do the heavy lifting in real text processing — one breaks a string into a list, the other glues a list back into a string. They're opposites, and the trick is keeping straight which one gives you a list and which one gives you a string."
.split() — string → list (everyone types each line and runs it):
print("the cat sat".split()) # ['the', 'cat', 'sat']
Run-verified output:
['the', 'cat', 'sat']
".split() with no argument breaks the string at the spaces and hands back a list of the pieces. Notice the square brackets and the quotes around each word — that's a list of strings, exactly like Week 9."
You can split on something other than spaces by passing a separator:
print("red,green,blue".split(",")) # ['red', 'green', 'blue']
Output (run-verified):
['red', 'green', 'blue']
.join() — list → string (the inverse):
print(" ".join(["the", "cat", "sat"])) # the cat sat
Output (run-verified):
the cat sat
"Read it as: the separator string " " joins the list. The string you call .join on goes between every pair of items. "-".join(["a","b","c"]) gives a-b-c."
print("-".join(["a", "b", "c"])) # a-b-c
Output (run-verified): a-b-c.
The code-along build — count the words in a sentence: this is your first real text algorithm, and it's two methods working together.
def count_words(sentence):
return len(sentence.split())
print(count_words("the quick brown fox jumps"))
Trace it: .split() turns the sentence into a 5-item list ['the', 'quick', 'brown', 'fox', 'jumps'], then len(...) counts the list. Output (run-verified):
5
"Split into words, count the words. That's it. Run it on your own sentence."
The two-line memory hook (put it on a slide): .split() makes a list; .join() makes a string.
Segment 4 — Trace This Code: Predict the Method Results (20 min) · Session 1 closes (~75)
Set it up: "Before we run a method, a real programmer predicts what it returns — and whether it returns a list or a string. Let's trace, then run to check."
Worked trace #1 — .split() returns a list:
print("a,b,c,d".split(","))
- Trace: split at each comma → four pieces, packaged as a list.
- Predicted:
['a', 'b', 'c', 'd']. Run it. Actual (run-verified):
['a', 'b', 'c', 'd']
Worked trace #2 — .join() returns a string:
print("/".join(["2026", "11", "15"]))
- Trace: the separator
"/"goes between each item → one string. - Output (run-verified):
2026/11/15
"Same data, opposite direction. .split() gave us a list; .join() gives us back a string."
Worked trace #3 — chaining for a real job (clean + normalize):
s = " Hello, WORLD! "
print(s.strip().lower())
- Trace:
.strip()returns"Hello, WORLD!"(spaces gone); then.lower()runs on that result →"hello, world!". Methods chain left to right. - Output (run-verified):
hello, world!
"This is exactly the hook string from the start of class, normalized in one line — trim, then lowercase. Cleaning input before you store or compare it is one of the most common things you'll ever write."
Quick interaction (rapid-fire, ~5 min): put three method calls on a slide; for each, students predict the output and say "list or string?" solo (20 sec), then you run it. Suggested with run-verified outputs: print("one two three".split()) → ['one', 'two', 'three'] (a list); print(len("one two three".split())) → 3; print("Python"[::-1]) → nohtyP (reverse with slicing).
Segment 5 — Strings Are Immutable: Methods Return a NEW String (22 min) · Session 2 opens
Hook back in: "Here's the idea that quietly breaks more beginner programs than any other this week. You'll call a method, it'll look like nothing happened, and the bug is invisible — until you understand immutability."
Plain language first. A string is immutable: once it exists, it cannot be changed. So what does .upper() do? It builds and returns a brand-new string and leaves the original exactly as it was. If you don't catch that new string in a variable, it vanishes.
The signature demo (put it on a slide, predict before running):
s = "Hello"
s.upper()
print(s)
- Predict: most of the room says
HELLO— we just called.upper(), right? Run it. Actual output (run-verified):
Hello
"Read that twice. We called .upper(), and s is still Hello. The method returned a new string "HELLO" — but we threw it away. We never stored it. The original s was never touched, because strings can't be touched."
The fix — reassign:
s = "Hello"
s = s.upper()
print(s)
Output (run-verified):
HELLO
"s = s.upper() means: run .upper(), get the new string back, and point s at it. Now s is HELLO. The rule: if you want to keep a method's result, reassign it."
Prove it doesn't mutate (one more, run-verified):
s = "hi"
print(s.upper()) # the new string -> HI
print(s) # the original -> hi
The method call prints HI (the new string), but s itself prints hi — untouched. Output (run-verified): HI then hi.
Land the key idea (slide): Every string method returns a new string; none of them change the original. .upper(), .lower(), .strip(), .replace() — all of them. To keep the result you must catch it (s = s.method()) or use it right away (print(s.method())).
Misconception + cure:
- ❌ "s.upper() changes s."
✅ Cure: it returns a new string and leaves s alone. Strings are immutable. Write s = s.upper() to keep it. When unsure, run it and print the original.
Segment 6 — Spot & Fix the Bug: Forgot to Reassign (18 min)
Set it up: "Here's a program that's supposed to clean a user's answer but doesn't. The code looks right. Let's debug it — find the bug, predict the fix, run to confirm."
The buggy program (put it on a slide exactly as is):
name = " bob "
name.strip()
print("[" + name + "]")
Debug it out loud:
1. Run it. Output (run-verified): [ bob ] — the spaces are still there.
2. We called .strip(). So why didn't the spaces go away? Because .strip() returned a new, trimmed string "bob" — and we threw it away. We never stored it. name is immutable, so it's unchanged.
3. The bug: the result of name.strip() was never reassigned. The method ran; its return value was discarded.
4. The fix, then run to confirm:
name = " bob "
name = name.strip()
print("[" + name + "]")
Output (run-verified):
[bob]
Land the key idea: a string method on a line by itself usually does nothing useful — its whole point is the value it returns. If you don't capture or use that return value, you wrote a line that computes an answer and immediately forgets it. The cure is one habit: reassign (s = s.method()) whenever you want to keep the change.
A second quick bug (let the room solve it):
text = "Quiet Please"
text.lower()
print(text)
Run-verified output: Quiet Please (unchanged — same bug). The fix: text = text.lower() → prints quiet please.
Segment 7 — Misconceptions Round-Up + Quick Interaction (20 min)
Name the misconceptions out loud, then cure each:
- ❌ "A string method changes the original string."
✅ Cure: it returns a new string; the original is immutable. Reassign to keep the result. - ❌ "
.split()and.join()both give me a string."
✅ Cure:.split()gives a list;.join()gives a string. They're inverses. - ❌ "
.replace("a","o")only changes the firsta."
✅ Cure:.replacechanges all matches:"banana".replace("a","o")→bonono. Run it. - ❌ "
.find()returnsTrue/False."
✅ Cure:.find()returns an index (a number), or-1if the substring isn't there..startswith()is the one that returnsTrue/False. - ❌ "To reverse a string I need a loop."
✅ Cure: slicing does it in one move:"hello"[::-1]→olleh. (A loop also works, but the slice is the idiom.)
Interaction — Predict-then-Run (rapid-fire, ~8 min): put four programs on a slide; students predict each output solo (30 sec), compare with a neighbor (1 min), then you run all four. Suggested with run-verified outputs:
- word = "cat" then word.upper() then print(word) → cat (immutability — the call is discarded)
- print("mississippi".count("s")) → 4
- print("stop"[::-1]) → pots
- print("red,green,blue".split(",")) → ['red', 'green', 'blue']
Tally how many the room got right — celebrate the misses on the immutability one as "this is why we reassign, and why we run code."
Segment 8 — Technology Workflow + AI-Critique, Callback & Hand-off (18 min) · Session 2 closes (~75)
Technology workflow — the everyday loop for text:
1. Open the free online Python environment (link in the readings). Type your code.
2. Call a method; print the result AND the original so you can see whether it changed (it won't — but seeing it cements immutability).
3. To watch a method return a new string while the original stays put, paste the snippet into Python Tutor and step forward — you'll see the new string appear without altering the first.
4. Make one change (usually: add the missing s =), run again.
AI-critique moment (students verify, not consume):
Paste this to an approved chatbot: "In Python, after
s = 'cat'; s.replace('c','h'), what iss? And what does'a, b, c'.split()return?"
Then check by running both yourself. Chatbots are especially slippery on strings: they'll confidently claim.replace()or.upper()changed the original (it didn't —sis still'cat'), or they'll mis-split"a, b, c"on whitespace and report['a', 'b', 'c']when.split()with no separator actually returns['a,', 'b,', 'c'](the commas stay attached). Your job all semester: the tool drafts, you run it and judge. This is exactly how the weekly Lecture Tutorial and Coding Lab work — you catch the model, not trust it.
Callback + tease:
- Callback: "Last week you finished collections — lists, tuples, dicts, and sets. The list came back today the moment .split() handed you one. Strings, like tuples, are immutable — which is why methods return new strings instead of changing them."
- Tease next week: "So far all our text lives inside the program. Next week we read text from a file and write it back out — and we meet what happens when the file isn't there: exceptions and try/except. We'll open files safely with with."
Hand-off (the week's graded work):
- Lecture Tutorial 11 (AI tutor, share-link submission) — string methods, immutability, and text algorithms.
- Quiz 11 and Discussion 11 ("Reading What We Write: Privacy & Text at Scale") and Assignment 11 ("Text Toolkit").
- Coding Lab 11 — "Take It Apart, Put It Back" — write a text-processing function, run a predict-then-run method table, and fix a "forgot to reassign" immutability bug.
Instructor FAQ — Common Stumbles
| Student says / does | Quick cure |
|---|---|
"I called .upper() but nothing changed." |
The method returns a new string; you discarded it. Write s = s.upper() (reassign). Strings are immutable. |
"s = s.split() then s.upper() crashes." |
After .split(), s is a list, not a string — list has no .upper(). Keep the names straight: split → list. |
Thinks .split() returns a string. |
It returns a list (square brackets). .join() is the one that returns a string. They're inverses. |
Thinks .replace("a","o") changes only the first match. |
.replace replaces all matches: "banana".replace("a","o") → bonono. Run it. |
Uses .find() in an if expecting True/False. |
.find() returns an index or -1. For a yes/no, use in or .startswith(). Run both to see. |
| Reverses a string with a clumsy loop. | Slicing: s[::-1]. Show "hello"[::-1] → olleh. |
"a, b, c".split() "should" drop the commas. |
.split() with no separator splits on whitespace only — the commas stay: ['a,', 'b,', 'c']. Pass ", " to split on the comma-space. |
| "I'll just trust what the chatbot said the method returns." | On strings, chatbots are wrong often (immutability, whitespace splitting). Run it and read the real result. |
Scope flag
This outline stays within Objective 7 (strings): the core string methods, immutability (methods return a new string), and simple text algorithms (count words, count a character, find/replace, reverse with s[::-1]). It uses only this-week constructs plus prior-week ones (variables, print, len, indexing/slicing from Week 3, functions from Week 7, lists from Week 9). Files, try/except, and reading text from disk are Week 12 and only teased here; regular expressions are beyond CS1 scope and not used. Python and its string methods are referenced factually; the instructor and institution remain fictional. Every method result and output shown was produced by running the code.
~ Prof. Okafor's edition · Fall 2026 · built with thecoursemaker.com