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.2

2. 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.3

3. What happens when you execute name = "Alice"; name[0] = "B"?

  • A) name becomes "Blice"
  • B) Python prints a warning but makes the change
  • C) A TypeError is raised
  • D) A ValueError is 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.4

4. 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.4

5. 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.5

6. 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.5

7. 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.5

8. 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.5

9. 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.7

10. 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.8

Section 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.4

13. 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.5

15. 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.9

Section 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