Quiz: Strings — Text Processing and Manipulation
Test your understanding before moving on. Target: 70% or higher to proceed confidently.
Section 1: Multiple Choice (1 point each)
1. What does "Python"[2] evaluate to?
- A)
"P" - B)
"y" - C)
"t" - D)
"th"
Answer
**C)** `"t"` *Why C:* Python uses zero-based indexing: P=0, y=1, t=2. *Why not A:* That would be index 0. *Why not B:* That would be index 1. *Why not D:* Indexing returns a single character, not two. *Reference:* Section 7.22. What does "Hello, World!"[7:12] evaluate to?
- A)
"World!" - B)
"World" - C)
" World" - D)
"orld!"
Answer
**B)** `"World"` *Why B:* Index 7 is 'W', and the slice goes up to but *not including* index 12. Characters at indices 7, 8, 9, 10, 11 spell "World". *Why not A:* That would require going to index 13 (or using `[7:]`). *Why not C:* The space is at index 6, not 7. *Why not D:* That would start at index 8. *Reference:* Section 7.33. What happens when you execute name = "Alice"; name[0] = "B"?
- A)
namebecomes"Blice" - B) Python prints a warning but makes the change
- C) A
TypeErroris raised - D) A
ValueErroris raised
Answer
**C)** A `TypeError` is raised *Why C:* Strings are immutable — they don't support item assignment. Python raises `TypeError: 'str' object does not support item assignment`. *Why not A:* Strings cannot be modified in place. *Why not B:* Python doesn't issue warnings for type errors — it raises exceptions. *Why not D:* The error is about the *type* of operation (assignment to an immutable), not the *value*. *Reference:* Section 7.44. Which of the following correctly changes greeting from "Hello" to "Jello"?
- A)
greeting[0] = "J" - B)
greeting.replace("H", "J") - C)
greeting = "J" + greeting[1:] - D) Both B and C
Answer
**C)** `greeting = "J" + greeting[1:]` *Why C:* This creates a new string by concatenating "J" with "ello" and reassigns it to `greeting`. *Why not A:* Strings are immutable; item assignment raises TypeError. *Why not B:* `replace()` creates a new string but doesn't *assign* it back to `greeting`. Without `greeting = greeting.replace("H", "J")`, the variable is unchanged. *Why not D:* B by itself doesn't save the result. *Reference:* Section 7.45. What does " hello ".strip() return?
- A)
"hello " - B)
" hello" - C)
"hello" - D)
"hello "(one trailing space)
Answer
**C)** `"hello"` *Why C:* `strip()` removes all leading *and* trailing whitespace. *Why not A:* That's what `lstrip()` does. *Why not B:* That's what `rstrip()` does. *Why not D:* `strip()` removes *all* leading and trailing whitespace, not just one space. *Reference:* Section 7.56. What does "a,b,,c".split(",") return?
- A)
["a", "b", "c"] - B)
["a", "b", "", "c"] - C)
["a,b,,c"] - D)
["a", "b", "c", ""]
Answer
**B)** `["a", "b", "", "c"]` *Why B:* `split(",")` splits at every comma. Between the two consecutive commas, there's an empty string. *Why not A:* This would discard the empty segment. `split()` with a specific separator preserves empty strings. *Why not C:* That would happen only if splitting on a character not in the string. *Why not D:* The last element would only be empty if the string ended with a comma. *Reference:* Section 7.57. What is the value of "-".join(["2025", "03", "14"])?
- A)
"2025-03-14" - B)
"-2025-03-14-" - C)
["2025", "-", "03", "-", "14"] - D)
"2025", "03", "14"
Answer
**A)** `"2025-03-14"` *Why A:* `join()` places the separator (`"-"`) between each element of the list, producing a single string. *Why not B:* `join()` doesn't add the separator at the beginning or end. *Why not C:* `join()` returns a string, not a list. *Why not D:* `join()` returns one string, not separate values. *Reference:* Section 7.58. What does "hello world".find("xyz") return?
- A)
0 - B)
False - C)
-1 - D) Raises
ValueError
Answer
**C)** `-1` *Why C:* `find()` returns -1 when the substring is not found. *Why not A:* 0 would mean the substring was found at index 0. *Why not B:* `find()` returns an integer, not a boolean. *Why not D:* `find()` never raises an exception — that's `index()` behavior. *Reference:* Section 7.59. What does "3.14".isdigit() return?
- A)
True - B)
False - C)
3.14 - D) Raises
TypeError
Answer
**B)** `False` *Why B:* The decimal point `.` is not a digit, so `isdigit()` returns False. *Why not A:* `isdigit()` requires *every* character to be a digit. *Why not C:* `isdigit()` returns a boolean, not a number. *Why not D:* `isdigit()` works on any string without raising errors. *Reference:* Section 7.710. What does f"{42:>10d}" produce?
- A)
"42 " - B)
" 42" - C)
" 42 " - D)
"0000000042"
Answer
**B)** `" 42"` *Why B:* `>` means right-align, `10` is the field width, and `d` is integer format. The number is right-aligned in a 10-character-wide field, padded with spaces on the left. *Why not A:* That would be left-aligned (`<`). *Why not C:* That would be centered (`^`). *Why not D:* That would require a zero-fill character (`f"{42:010d}"`). *Reference:* Section 7.8Section 2: Short Answer (2 points each)
11. Write a single expression that reverses the string "Python" to produce "nohtyP".
Answer
"Python"[::-1]
The slice `[::-1]` steps backwards through the entire string.
*Reference:* Section 7.3
12. Explain in 2-3 sentences why strings are immutable in Python. Give one practical benefit of immutability.
Answer
Strings are immutable because once created, their contents cannot be modified — any "change" creates a new string object. This is a deliberate design decision in Python. One practical benefit: **safety** — when you pass a string to a function, you can be certain the function cannot alter your original string, eliminating an entire category of bugs. Other valid benefits include: strings can be used as dictionary keys (hashability), memory optimization through string interning, and thread safety. *Reference:* Section 7.413. Write code that takes the string "alice,bob,carol" and produces the string "Alice | Bob | Carol".
Answer
names = "alice,bob,carol"
parts = names.split(",")
capitalized = []
for name in parts:
capitalized.append(name.capitalize())
result = " | ".join(capitalized)
print(result) # Output: Alice | Bob | Carol
*Reference:* Section 7.5
14. What is the difference between find() and index() when the substring is not present?
Answer
`find()` returns `-1` when the substring is not found. `index()` raises a `ValueError` exception when the substring is not found. Both return the same index when the substring *is* found. Use `find()` when you want to check for existence without risking an exception. Use `index()` when the substring *should* be there and its absence indicates a bug. *Reference:* Section 7.515. What does len("Hello\n") return, and why?
Answer
It returns `6`. The string contains 6 characters: `H`, `e`, `l`, `l`, `o`, and the newline character `\n`. Although `\n` is written as two characters in the source code, it represents a single newline character in the string. *Reference:* Section 7.9Section 3: Code Tracing (2 points each)
16. What does this code print?
text = "Hello, World!"
result = ""
for char in text:
if char.isupper():
result += char
print(result)
Answer
HW
The loop iterates through each character. `isupper()` returns True for `'H'` and `'W'`, which are the only uppercase letters. These are accumulated into `result`.
*Reference:* Sections 7.5, 7.6
17. What does this code print?
words = "the quick brown fox".split()
acronym = ""
for w in words:
acronym += w[0].upper()
print(acronym)
Answer
TQBF
The code splits the sentence into words, takes the first character of each word (`w[0]`), converts it to uppercase, and concatenates them.
*Reference:* Sections 7.2, 7.5, 7.6
18. What does this code print?
data = "name:Alice;age:30;city:Boston"
pairs = data.split(";")
for pair in pairs:
key, value = pair.split(":")
print(f"{key:>6s} = {value}")
Answer
name = Alice
age = 30
city = Boston
The outer split breaks on `;` to get `["name:Alice", "age:30", "city:Boston"]`. Each pair is then split on `:` to separate key and value. The f-string right-aligns the key in a 6-character field.
*Reference:* Sections 7.5, 7.8
Section 4: Debugging (2 points each)
19. Find and fix the bug in this code:
def clean_input(text):
"""Remove leading/trailing whitespace and convert to lowercase."""
text.strip()
text.lower()
return text
result = clean_input(" Hello ")
print(result) # Prints " Hello " instead of "hello"
Answer
The bug is that `strip()` and `lower()` return *new* strings — they don't modify the original (because strings are immutable). The return values are being discarded. **Fix:**def clean_input(text):
"""Remove leading/trailing whitespace and convert to lowercase."""
return text.strip().lower()
This is one of the most common beginner mistakes with strings. Always remember: string methods return new strings.
*Reference:* Section 7.4
20. Find and fix the bug in this code:
def get_extension(filename):
"""Return the file extension (e.g., '.txt')."""
dot_pos = filename.find(".")
return filename[dot_pos:]
print(get_extension("report.pdf")) # Works: ".pdf"
print(get_extension("archive.tar.gz")) # Bug: ".tar.gz" not ".gz"
print(get_extension("no_extension")) # Bug: returns "no_extension"
Answer
Two bugs: 1. `find()` returns the *first* dot. Use `rfind()` to find the *last* dot. 2. When there's no dot, `find()` returns -1. `filename[-1:]` returns the last character instead of indicating no extension. **Fix:**def get_extension(filename):
"""Return the file extension, or '' if none."""
dot_pos = filename.rfind(".")
if dot_pos == -1:
return ""
return filename[dot_pos:]
*Reference:* Sections 7.3, 7.5