1. Reference Guide

Key Terms: Mutable vs. Immutable

Term Definition Examples
Mutable An object whose contents can be changed in place after it’s created — no new object is made, the same one is edited. list, dict, set
Immutable An object whose contents cannot be changed in place. Any “edit” builds a brand-new object in memory and leaves the original untouched. str, tuple, int, float

A string is an ordered, immutable sequence of characters. You never edit a string in place — every “change” actually builds a brand-new string and throws the old one away.


Interceptor Skill Reference

Skill What it lets an interceptor do
Indexing & slicing Pull out exact characters or chunks of a message by position
String methods Clean up noisy text, search for keywords, split and rejoin fragments
Concatenation & formatting Rebuild a decoded message and produce a readable report

2. LxD Cycle Process

Empathize: Students often think strings behave like lists they can edit directly, get tripped up by zero-indexing and negative indices, and forget that .upper(), .replace(), and every other string method return a brand-new string instead of changing the original.

Define:

  • POV: CSP students need a concrete, hands-on way to feel why strings are ordered and immutable, not just memorize indexing rules from a slide.
  • Learning Goal: Students will index and slice strings to extract characters and substrings, apply built-in string methods to clean and search text, and use concatenation and formatting to build new strings out of pieces.

Ideate:

  • HMW Question: How might we make abstract indexing and slicing rules feel like a real, useful skill instead of trivia to memorize?
  • Activity: Three short cycles of a tech talk followed by a code runner exercise, framed as decoding intercepted transmissions, ending in a combined homework mission.

Prototype & Test: A trial run with a professor reviewer surfaced two gaps in the first draft — see Section 8 for what was found and how it was fixed.


3. College Board Requirements

AP CSP Big Idea 3: Algorithms and Programming (AAP), Topic 3.4 Strings. Quoted from the course and exam description (College Board, 2023):

  • AAP-1.C.4 “A string is an ordered sequence of characters.”
  • AAP-2.D.1 “String concatenation joins together two or more strings end-to-end to make a new string.”
  • AAP-2.D.2 “A substring is part of an existing string.”

Cycle 1 (indexing & slicing) builds the “ordered sequence” idea from AAP-1.C.4 and the substring concept from AAP-2.D.2. Cycle 3 (concatenation & formatting) is a direct application of AAP-2.D.1. Cycle 2 (string methods) extends both essential knowledge statements into the built-in operations Python provides for cleaning and searching text.


4. Lesson Plan

Learning Objective: By the end of this lesson, you will be able to index and slice strings to extract specific characters or substrings, apply string methods to clean, search, and transform text, and use concatenation and f-strings to build new strings from smaller pieces.

Success Criteria: You can predict the exact output of an indexing or slicing expression, choose the correct string method for a cleaning or searching task, and combine slicing, methods, and formatting to solve a multi-step string problem.

Cycle Tech Talk (1–2 min) Popcorn Hack (5 min)
1 Indexing & slicing Extract a hidden message by position
2 String methods (clean & search) Scrub and search a noisy transmission
3 Concatenation & formatting Rebuild a decoded report
Homework   Crack the Final Transmission

5. Code Examples

A. Quote Styles

A string is Python’s way of representing text: any sequence of characters — letters, numbers, symbols, even spaces — wrapped in quotes so Python knows it’s data, not code.

You can create a string with single quotes, double quotes, or triple quotes (for text that spans multiple lines):

Code Runner Challenge

Demo - Create strings with different quote styles

View IPYNB Source
message = "Hello"

also_a_string = 'Hello'

multiline = """Hello,
world!"""
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Single and double quotes work the same — pick whichever lets you avoid escaping a quote inside the string ("it's a valid spec" is easier to read than 'it\'s a valid spec').

Run the demo below to see the different quote styles in action.

Code Runner Challenge

Demo - Try to edit a string in place and watch it fail

View IPYNB Source
# CODE_RUNNER: Demo - Create strings with different quote styles

single = 'Auto Racing'
double = "Auto Racing"
multiline = """SPEC 1.1
FLYWHEEL"""

print(single == double)   # True -> the quote style you pick doesn't change the value
print(type(single))       # <class 'str'> -> both quote styles make the same type
print(len(single))        # ordered sequence -> it has a length, character by character
print(multiline)          # triple quotes preserve the line break inside the string
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

B. Immutability

Once created, a string is ordered and immutable — see the Key Terms table in the Reference Guide above for the exact definitions. You never edit a string in place — every “change” actually builds a brand-new string and throws the old one away. Run the demo below and watch it fail on purpose.

Code Runner Challenge

Demo - Build a new string instead of editing in place

View IPYNB Source
# CODE_RUNNER: Demo - Try to edit a string in place and watch it fail

message = "HELLO"
message[0] = "J"   # TypeError: 'str' object does not support item assignment
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

That’s the error you’ll hit every time you try to change a character in place. The fix is to build a brand-new string instead:

Code Runner Challenge

Demo - Index and slice an SFI record string

View IPYNB Source
# CODE_RUNNER: Demo - Build a new string instead of editing in place

message = "HELLO"
fixed = "J" + message[1:]   # slice off the "H", then glue "J" onto the front
print(fixed)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

6. Hacks & Practice Tasks

You are a signal interceptor. Every transmission that crosses your desk is just a Python string. Across the three cycles below you’ll use the skills from the Reference Guide to read, clean, search, and rebuild intercepted text — then combine all three skills to crack one final transmission for homework.

Prepare your submission IPYNB

Complete this quick-start flow so you can begin in about 2 minutes.

  1. Create a new notebook in your portfolio homework area: _notebooks/homework.
  2. Add one raw cell at the top with the frontmatter below.
  3. Add a code cell for each Popcorn Hack and the Homework. Keep the # CODE_RUNNER: comment as the first line of each code cell.
  4. Run each cell and check the output before submitting.
---
layout: post
title: 3.4 Strings HW
categories: [Python]
lesson_language: Python
lesson_topic: Strings HW
lesson_part: interactive
lesson_type: lesson
permalink: /python/strings-intercepters-hw
author: githubID
---

Submission Safety Rules (Read First)

[!IMPORTANT] To avoid grading errors, follow these rules exactly:

  • Keep the # CODE_RUNNER: comment as the first line of each submission cell.
  • Your code must run in the code runner with no errors.
  • This lesson needs no imports at all — indexing, slicing, and every string method used here are built into the str type.
  • Do not use input(). The code runner cannot type answers for you.

Cycle 1 Tech Talk: Indexing & Slicing (2 minutes)

Every character in a string has a position, called an index, starting at 0 for the first character. Negative indices count backward from the end, starting at -1 for the last character.

Slicing grabs a whole chunk at once with string[start:stop:step]. The start index is included, the stop index is excluded, and step controls direction and skipping. Run the demo below, then try editing record and the slice ranges to see how the output changes.

Code Runner Challenge

Popcorn Hack 1 - Extract the hidden message using indexing and slicing

View IPYNB Source
# CODE_RUNNER: Demo - Index and slice an SFI record string

record = "RACING-SPEC-1.1"

print(record[0])       # 'R'  -> first character, index 0
print(record[-1])      # '1'  -> last character, index -1
print(record[7:11])    # 'SPEC' -> characters 7 up to (not including) 11
print(record[::2])     # every OTHER character, start to end
print(record[::-1])    # the whole string, reversed
print(len(record))     # 15  -> total number of characters
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Python vs. College Board Pseudocode

The AP CSP Exam Reference Sheet indexes sequences starting at 1, not 0 — this is the single biggest gotcha when translating pseudocode into Python.

Form First character of record
Python first = record[0]
College Board pseudocode first ← record[1]

College Board pseudocode has no negative-indexing shortcut like Python’s record[-1] — it only ever counts up from 1.

  • record[7:11] never includes index 11 — that’s the single most common slicing bug.
  • record[a:b] always returns a new string; record itself never changes.
  • If you leave out start or stop, Python assumes “the beginning” or “the end.”

Tech Talk: Why Immutability Matters

Because strings can’t be changed in place, “editing” a message really means slicing out the parts you want to keep and gluing them back together with pieces you want to add. That’s the whole game for the rest of this lesson.

Popcorn Hack 1: Extract the Hidden Message (5 minutes)

Task: An intercepted transmission has a real message hidden inside decoy characters at fixed positions. Use only indexing and slicing — no string methods yet — to pull the real words out.

Code Runner Challenge

Demo - Clean and search a string with methods

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 1 - Extract the hidden message using indexing and slicing

transmission = "xxSIGNALxxxCONFIRMEDxx77xxDELTA"

# TODO 1: Use slicing to pull out "SIGNAL" (it starts at index 2 and is 6 characters long)
word_1 = ""
print("Word 1:", word_1)

# TODO 2: Use slicing to pull out "CONFIRMED" (it starts right after "SIGNALxxx")
word_2 = ""
print("Word 2:", word_2)

# TODO 3: Use NEGATIVE indexing/slicing to pull out "DELTA" (it is the last 5 characters)
word_3 = ""
print("Word 3:", word_3)

# TODO 4: Use len() to print how many characters are in the FULL transmission
print("Total length:", 0)

# TODO 5: Use a slice with a step of 2 (transmission[::2]) to print every other character.
#         Look closely: is any part of the hidden message still visible in this pattern?
print("Every other character:", "")
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Cycle 2 Tech Talk: String Methods — Clean & Search (2 minutes)

A string method is a built-in procedure attached to every string with .method_name(). Just like slicing, every method below returns a new string (or a new list, or a True/False) — none of them ever change the original. Run the demo, then swap in your own noisy string.

Code Runner Challenge

Demo - Split real-world separators (CSV and Markdown table)

View IPYNB Source
# CODE_RUNNER: Demo - Clean and search a string with methods

raw = "   SFI-BACKEND says: the SPEC is DUPLICATE!!!  "

clean = raw.strip()                     # removes leading/trailing whitespace
print(clean)

print(clean.lower())                    # a lowercase COPY
print(clean.replace("!", ""))           # a copy with "!" removed
print(clean.split(":"))                 # splits into a LIST of pieces on ":"
print("duplicate" in clean.lower())     # case-insensitive search with `in`
print(clean.find("SPEC"))               # index where "SPEC" starts, or -1 if missing
print(clean.count("S"))                 # how many times "S" appears
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...
Method What it does
.strip() Removes whitespace (or given characters) from both ends
.upper() / .lower() Returns an all-caps / all-lowercase copy
.replace(old, new) Returns a copy with every old swapped for new
.split(sep) Breaks a string into a list of strings at every sep
"x" in s True/False — is x found anywhere inside s?
.find(sub) Index of the first match, or -1 if not found
.count(sub) How many non-overlapping times sub appears

Watch out: .replace() and .strip() don’t change raw — they hand back a new string that you must save into a variable, or the cleanup is lost.

Real-World Separators: CSV and Markdown Tables

Custom markers like ## don’t show up in the real world. Real records almost always use standard separators:

  • CSV (comma-separated values) — the standard format for spreadsheets and data exports: "Auto Racing,1.1,Replacement Flywheels,2001-11-09"
  • Markdown tables — separate columns with a pipe |: "Auto Racing | 1.1 | Replacement Flywheels | 2001-11-09"

.split() works exactly the same either way — you just pass in the character the format actually uses.

Code Runner Challenge

Popcorn Hack 2 - Clean and search a noisy transmission using string methods

View IPYNB Source
# CODE_RUNNER: Demo - Split real-world separators (CSV and Markdown table)

csv_line = "Auto Racing,1.1,Replacement Flywheels,2001-11-09"
fields = csv_line.split(",")                                   # comma -> CSV
print(fields)

table_row = "Auto Racing | 1.1 | Replacement Flywheels | 2001-11-09"
columns = [piece.strip() for piece in table_row.split("|")]    # pipe -> Markdown table
print(columns)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Popcorn Hack 2: Scrub and Search a Noisy Transmission (5 minutes)

Task: This transmission is full of noise — stray punctuation, extra whitespace, and mismatched case. Clean it up and search it using only string methods.

Code Runner Challenge

Demo - Concatenation, str(), f-strings, and join

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 2 - Clean and search a noisy transmission using string methods

noisy = "   ...AGENT>>>Falcon---reports: the PACKAGE has ARRIVED!!!   "

# TODO 1: Use .strip() to remove the leading/trailing whitespace. Save it as trimmed.
trimmed = noisy
print("Trimmed:", repr(trimmed))

# TODO 2: Use .replace() (you may need it more than once) to remove every ">", "-", and "!" character.
#         Save the result as cleaned.
cleaned = trimmed
print("Cleaned:", cleaned)

# TODO 3: Use .lower() to make an all-lowercase COPY of cleaned. Save it as lowered.
lowered = cleaned
print("Lowered:", lowered)

# TODO 4: Use the `in` operator on lowered to check whether "arrived" appears anywhere in the message.
has_arrived = False
print("Contains 'arrived':", has_arrived)

# TODO 5: Use .split() with no arguments on cleaned to break it into a list of words.
#         Save it as words, then print how many words there are with len().
words = []
print("Word count:", len(words))
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Cycle 3 Tech Talk: Concatenation & Formatting (2 minutes)

Concatenation glues strings together with +. Python will not silently convert other types for you — mixing a string with an int or float using + raises a TypeError, so you must convert it first with str(). Run the demo below to see all three styles side by side.

Code Runner Challenge

Demo - Build a JSON-style line that mixes separators

View IPYNB Source
# CODE_RUNNER: Demo - Concatenation, str(), f-strings, and join

part = "Flywheel Assembly"
status = "validated"
count = 3

report = part + " status: " + status                        # + only works string-to-string
report_with_number = part + " matched " + str(count) + " specs"   # str() converts the int first
print(report)
print(report_with_number)

# f-strings are the cleanest way to mix types - no manual + or str() needed
report_f = f"{part} status: {status} ({count} specs matched)"
print(report_f)

spec_numbers = ["1.1", "1.2", "2.1"]
print("-".join(spec_numbers))     # glues a LIST into ONE string, with "-" between pieces
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Python vs. College Board Pseudocode

String concatenation with + and College Board pseudocode’s assignment arrow ← map onto each other directly:

Form Concatenate two strings
Python report = part + " status: " + status
College Board pseudocode report ← part + " status: " + status

The ← arrow is how the AP CSP Exam Reference Sheet always writes assignment — Python’s = means exactly the same thing.

Three ways to build a combined string, from clunkiest to cleanest:

Style Example Notes
+ concatenation "Score: " + str(score) Every non-string value needs str() first
.format() "Score: {}".format(score) No manual str() needed, but harder to read
f-string f"Score: {score}" Cleanest — values are converted automatically

"sep".join(list_of_strings) is the reverse of .split() — it’s the standard way to turn a list of pieces back into one string.

Bonus: JSON Mixes Separators Too

JSON (JavaScript Object Notation) is the standard format for sending structured data between programs. A single JSON object mixes several separators at once: { } wrap the whole thing, : separates a key from its value, and , separates one key-value pair from the next.

f-strings make it easy to build a JSON-style line by hand. One gotcha: JSON’s true/false are lowercase, unlike Python’s True/False — convert booleans with str(value).lower() before dropping them in.

Code Runner Challenge

Popcorn Hack 3 - Build a decoded report using concatenation and formatting

View IPYNB Source
# CODE_RUNNER: Demo - Build a JSON-style line that mixes separators

import json

part = "Flywheel Assembly"
confidence = 87
spec_numbers = ["1.1", "1.2", "2.1"]
duplicate = True

joined_specs = "-".join(spec_numbers)      # turn the list into one dash-joined string first
json_line = json.dumps({
    "part": part,
    "confidence": confidence,
    "specs": joined_specs,
    "duplicate": duplicate,
})
print(json_line)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Popcorn Hack 3: Build a Decoded Report (5 minutes)

Task: Combine fragments recovered from the last two cycles into a single, formatted intercept report using concatenation, str(), f-strings, and .join().

Code Runner Challenge

Homework - Crack the Final Transmission using slicing, methods, and formatting

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 3 - Build a decoded report using concatenation and formatting

agent_name = "Falcon"
target_word = "MIDNIGHT"
confidence = 87          # a percentage, stored as an int
fragments = ["ALPHA", "SEVEN", "DELTA"]

# TODO 1: Use + concatenation to build: "Agent Falcon intercepted: MIDNIGHT"
headline = ""
print(headline)

# TODO 2: confidence is an int. Use str() and + concatenation to build: "Confidence: 87%"
confidence_line = ""
print(confidence_line)

# TODO 3: Rewrite the SAME line as confidence_line_fstring, but using an f-string this time
confidence_line_fstring = ""
print(confidence_line_fstring)

# TODO 4: Use "-".join(fragments) to combine the fragments list into one string
joined_fragments = ""
print("Joined fragments:", joined_fragments)

# TODO 5: Use an f-string to build ONE final report line combining headline, confidence_line,
#         and joined_fragments, in the form:
#         "REPORT: <headline> | <confidence_line> | Fragments: <joined_fragments>"
final_report = ""
print(final_report)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Homework Hack: Crack the Final Transmission

Task: One transmission is left, and it needs all three skills — indexing/slicing, string methods, and formatting — to fully decode. This time the transmission arrives the way real systems actually send data: as a comma-separated (CSV-style) row. Your finished program must:

  1. Clean and split it. Use .strip() to remove outer whitespace, then .split(",") to break the CSV row into fields — the same technique spreadsheets and data exports use.
  2. Extract by index. Use indexing on the resulting list to pull out the date, the agent codename, the raw message code, and the confidence score.
  3. Slice-check the date. Use slicing (not a method) to confirm the date field starts with the year "2026".
  4. Clean and search the message. Use .replace() to turn the dashes in the message code into spaces, then use .lower() and the in operator to check whether the word "dawn" appears anywhere in it.
  5. Rebuild it as a Markdown table row. Use an f-string with | separators to turn the decoded fields into one Markdown table row: | <date> | <agent> | <message> | <confidence>% |.
  6. Rebuild it as a JSON line. Use an f-string to build a JSON-style line for the same data — mixing { }, :, and , the way real systems pass structured data between programs. Remember: JSON booleans are lowercase (true/false), not Python’s True/False.
# CODE_RUNNER: Homework - Crack the Final Transmission using slicing, methods, and formatting

raw_transmission = "  2026-09-15,GHOST,THE-EAGLE-LANDS-AT-DAWN,87  "

# TODO 1: Use .strip() to remove the outer whitespace, then .split(",") to break it into fields.
#         Print segments. Since this is a real CSV row (no leading/trailing marker), there
#         should be exactly 4 fields and no stray empty strings.
segments = []
print("Segments:", segments)

# TODO 2: Use indexing on segments to pull out the date, agent, message code, and confidence.
date = ""
agent = ""
message_code = ""
confidence_str = ""
print("Date:", date, "| Agent:", agent, "| Message code:", message_code, "| Confidence:", confidence_str)

# TODO 3: Use SLICING (not a method) on date to confirm it starts with the year "2026".
year_check = ""
print("Year check:", year_check)

# TODO 4: Use .replace() to turn the dashes in message_code into spaces. Save it as message.
message = message_code

# TODO 5: Use .lower() and the `in` operator to check whether "dawn" appears anywhere in message.
found_dawn = False
print("Found 'dawn':", found_dawn)

# TODO 6: Use an f-string with "|" separators to build a Markdown table row of the decoded fields,
#         in the form:
#         "| <date> | <agent> | <message> | <confidence_str>% |"
markdown_row = ""
print("Markdown row:", markdown_row)

# TODO 7: Use an f-string to build a JSON-style line for the same fields, mixing "{", "}", ":", and ","
#         the way real systems pass structured data. Use str(found_dawn).lower() for the boolean, since
#         JSON uses lowercase true/false instead of Python's True/False. Form:
#         {"date": "<date>", "agent": "<agent>", "message": "<message>", "confidence": <confidence_str>, "contains_dawn": <found_dawn lowercase>}
json_line = ""
print("JSON line:", json_line)

7. Grading Plan (1 Point Total)

Classroom Rubric

Activity Points What earns the points
Popcorn Hacks (all 3) 0.3 (0.1 each) Student completed all TODOs in each Popcorn Hack and the cell runs without errors.
Homework — splitting 0.15 Correctly strips and splits the CSV transmission into fields on , — a real-world separator, not a made-up marker.
Homework — indexing 0.15 Correctly extracts the date, agent, message code, and confidence by index.
Homework — slicing 0.1 Correctly slices the date to confirm the year, without using a string method.
Homework — methods 0.15 Correctly replaces dashes with spaces and performs a case-insensitive search for “dawn”.
Homework — formatting 0.15 Builds a correct Markdown table row (pipe-separated) AND a JSON-style line (mixing { }, :, and ,) from the decoded fields.
Total 1.0  

Quick Validation Checklist

  • Present: # CODE_RUNNER: comment as the first line of each cell.
  • Present: at least one slicing expression that does NOT use a string method.
  • Present: at least three different string methods (for example .strip(), .split(), .replace(), .lower()).
  • Present: a Markdown-style table row (pipe-separated) and a JSON-style line (comma/colon/brace-separated) built from the decoded fields.
  • Absent: input(), any import statement, and errors when run.

8. Lesson Revisions & Feedback Evidence

Feedback Received: A trial run with a professor reviewer surfaced two gaps in the first draft. First, the homework’s ## marker didn’t resemble any real-world data format, so decoding it didn’t transfer to a skill students would actually reuse elsewhere. Second, the mutable/immutable contrast landed well as an example but was never formally defined as a term, so students without the vocabulary had nothing to anchor it to.

Revision Made: The homework was rebuilt around CSV commas, Markdown-table pipes, and a JSON line — real-world separators instead of a made-up marker. An explicit Key Terms callout was added to the Reference Guide, now Section 1 at the top of the lesson, so students have the mutable/immutable vocabulary before they need it.


References

College Board. (2023). AP Computer Science Principles: Course and Exam Description (Fall 2023 ed.). Big Idea 3: Algorithms and Programming, Topic 3.4: Strings (AAP-1.C.4, AAP-2.D.1, AAP-2.D.2). New York, NY: College Board.

CompuScholar, Inc. AP CSP Learning Objectives and Essential Knowledge alignment [Cross-reference]. https://www.compuscholar.com/docs/apcsp/AP_CSP_Topic_Cross_Reference.pdf