AP CSP 3.4 — Python Strings: Free-Response Quiz

This quiz focuses only on Python string operations (no JavaScript). Type your answers and click Check Answers.

  • Case-insensitive where appropriate
  • Quotes around answers are optional
  • True/False accepts yes/no, t/f, 1/0
%pip install ipywidgets

# Define password for Q8
password = "Escape123!"
password_length = len(password)

# Python-only Strings Quiz
from IPython.display import display, HTML, Javascript
import ipywidgets as widgets

print("🐍 Python Strings — Free-Response Quiz")
print("Answer the questions below and click Check Answers.\n")

# Q1: Slice
q1_label = widgets.HTML("<b>1. What does 'hello'[1:4] return?</b>")
q1 = widgets.Text(placeholder='e.g., ell')

# Q2: Length
q2_label = widgets.HTML("<b>2. What is len('Escape Room')?</b>")
q2 = widgets.Text(placeholder='Enter a number')

# Q3: Lowercase
q3_label = widgets.HTML("<b>3. What does 'Python'.lower() return?</b>")
q3 = widgets.Text(placeholder='e.g., python')

# Q4: Strip
q4_label = widgets.HTML("<b>4. If s = '   CS Rocks!  ', what does s.strip() return?</b>")
q4 = widgets.Text(placeholder='e.g., CS Rocks!')

# Q5: startswith (True/False)
q5_label = widgets.HTML("<b>5. Does 'algorithm' start with 'algo'?</b> (True/False)")
q5 = widgets.Text(placeholder='True/False')

# Q6: count
q6_label = widgets.HTML("<b>6. What is 'banana'.count('an')?</b>")
q6 = widgets.Text(placeholder='Enter a number')

# Q7: find
q7_label = widgets.HTML("<b>7. What index does 'debuggers'.find('bug') return?</b>")
q7 = widgets.Text(placeholder='Enter a number')

# Q8: password length (uses existing variable)
q8_label = widgets.HTML(f"<b>8. What is the length of the password '{password}'?</b>")
q8 = widgets.Text(placeholder='Enter a number')

submit_btn = widgets.Button(description='Check Answers', button_style='success', icon='check')
output = widgets.Output()

def parse_bool_like(s: str):
    v = s.strip().lower()
    if v in {'true','t','yes','y','1'}: return True
    if v in {'false','f','no','n','0'}: return False
    return None

def strip_quotes(s: str):
    return s.strip().strip("'").strip('"')

def clean_str(s: str):
    return s.strip().strip("'").strip('"')

def check_answers(btn):
    with output:
        output.clear_output()
        score, total = 0, 8
        print('📊 QUIZ RESULTS')
        print('='*40)

        # Q1
        a1 = clean_str(q1.value).lower()
        if a1 == 'ell':
            score += 1; print('✅ Q1: CORRECT')
        else:
            print('❌ Q1: INCORRECT — Correct: ell')

        # Q2 (len of 'Escape Room' is 11)
        a2 = clean_str(q2.value)
        if a2.isdigit() and int(a2) == 11:
            score += 1; print('✅ Q2: CORRECT')
        else:
            print('❌ Q2: INCORRECT — Correct: 11 (spaces count)')

        # Q3
        a3 = clean_str(q3.value).lower()
        if a3 == 'python':
            score += 1; print('✅ Q3: CORRECT')
        else:
            print("❌ Q3: INCORRECT — Correct: python")

        # Q4
        a4 = strip_quotes(q4.value)
        if a4 == 'CS Rocks!':
            score += 1; print('✅ Q4: CORRECT')
        else:
            print("❌ Q4: INCORRECT — Correct: CS Rocks!")

        # Q5
        a5 = parse_bool_like(q5.value)
        if a5 is None:
            print('⚠️ Q5: Could not parse. Please answer True/False.')
        elif a5 is True:
            score += 1; print('✅ Q5: CORRECT')
        else:
            print("❌ Q5: INCORRECT — Correct: True")

        # Q6
        a6 = clean_str(q6.value)
        if a6.isdigit() and int(a6) == 2:
            score += 1; print('✅ Q6: CORRECT')
        else:
            print("❌ Q6: INCORRECT — Correct: 2")

        # Q7 ('debuggers'.find('bug') is 2)
        a7 = clean_str(q7.value)
        if a7.isdigit() and int(a7) == 2:
            score += 1; print('✅ Q7: CORRECT')
        else:
            print("❌ Q7: INCORRECT — Correct: 2")

        # Q8 (password length)
        a8 = clean_str(q8.value)
        if a8.isdigit() and int(a8) == password_length:
            score += 1; print('✅ Q8: CORRECT')
        else:
            print(f"❌ Q8: INCORRECT — Correct: {password_length}")

        print('='*40)
        print(f'🎯 Your Score: {score}/{total}')
        print(f'📈 Percentage: {score/total*100:.1f}%')
        try:
            display(Javascript("localStorage.setItem('csp34_hw_py_quiz_tried','true');"))
        except Exception:
            pass

submit_btn.on_click(check_answers)

display(q1_label, q1, q2_label, q2, q3_label, q3, q4_label, q4, q5_label, q5, q6_label, q6, q7_label, q7, q8_label, q8, submit_btn, output)
Requirement already satisfied: ipywidgets in c:\users\rishabh jha\appdata\local\programs\python\python313\lib\site-packages (8.1.7)
Requirement already satisfied: comm>=0.1.3 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipywidgets) (0.2.3)
Requirement already satisfied: ipython>=6.1.0 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipywidgets) (9.6.0)
Requirement already satisfied: traitlets>=4.3.1 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipywidgets) (5.14.3)
Requirement already satisfied: widgetsnbextension~=4.0.14 in c:\users\rishabh jha\appdata\local\programs\python\python313\lib\site-packages (from ipywidgets) (4.0.14)
Requirement already satisfied: jupyterlab_widgets~=3.0.15 in c:\users\rishabh jha\appdata\local\programs\python\python313\lib\site-packages (from ipywidgets) (3.0.15)
Requirement already satisfied: colorama in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (0.4.6)
Requirement already satisfied: decorator in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (5.2.1)
Requirement already satisfied: ipython-pygments-lexers in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (1.1.1)
Requirement already satisfied: jedi>=0.16 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (0.19.2)
Requirement already satisfied: matplotlib-inline in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (0.1.7)
Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (3.0.52)
Requirement already satisfied: pygments>=2.4.0 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (2.19.2)
Requirement already satisfied: stack_data in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from ipython>=6.1.0->ipywidgets) (0.6.3)
Requirement already satisfied: wcwidth in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython>=6.1.0->ipywidgets) (0.2.14)
Requirement already satisfied: parso<0.9.0,>=0.8.4 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from jedi>=0.16->ipython>=6.1.0->ipywidgets) (0.8.5)
Requirement already satisfied: executing>=1.2.0 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from stack_data->ipython>=6.1.0->ipywidgets) (2.2.1)
Requirement already satisfied: asttokens>=2.1.0 in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from stack_data->ipython>=6.1.0->ipywidgets) (3.0.0)
Requirement already satisfied: pure-eval in c:\users\rishabh jha\appdata\roaming\python\python313\site-packages (from stack_data->ipython>=6.1.0->ipywidgets) (0.2.3)
Note: you may need to restart the kernel to use updated packages.
🐍 Python Strings — Free-Response Quiz
Answer the questions below and click Check Answers.




[notice] A new release of pip is available: 25.1.1 -> 25.2
[notice] To update, run: python.exe -m pip install --upgrade pip



HTML(value="<b>1. What does 'hello'[1:4] return?</b>")



Text(value='', placeholder='e.g., ell')



HTML(value="<b>2. What is len('Escape Room')?</b>")



Text(value='', placeholder='Enter a number')



HTML(value="<b>3. What does 'Python'.lower() return?</b>")



Text(value='', placeholder='e.g., python')



HTML(value="<b>4. If s = '   CS Rocks!  ', what does s.strip() return?</b>")



Text(value='', placeholder='e.g., CS Rocks!')



HTML(value="<b>5. Does 'algorithm' start with 'algo'?</b> (True/False)")



Text(value='', placeholder='True/False')



HTML(value="<b>6. What is 'banana'.count('an')?</b>")



Text(value='', placeholder='Enter a number')



HTML(value="<b>7. What index does 'debuggers'.find('bug') return?</b>")



Text(value='', placeholder='Enter a number')



HTML(value="<b>8. What is the length of the password 'Escape123!'?</b>")



Text(value='', placeholder='Enter a number')



Button(button_style='success', description='Check Answers', icon='check', style=ButtonStyle())



Output()

Part 2: Python Password Strength Practice

Here you will make a password strength analyzer in Python. Complete the program so it checks:

  • Password length ≥ 8 characters
  • Contains uppercase letters
  • Contains lowercase letters
  • Contains numbers
  • Contains special characters (!@#$%^&*)

Then calculate a strength score and display appropriate feedback.

Try to fix the code to set your own password level.

print("=== Password Strength Analyzer ===")

def analyze_password(password: str, min_length: int = 8, special_chars: str = "!@#$%^&*"):
    password_length = len(password)
    is_long_enough = password_length >= min_length
    has_uppercase = any(c.isupper() for c in password)
    has_lowercase = any(c.islower() for c in password)
    has_numbers = any(c.isdigit() for c in password)
    has_special = any(c in special_chars for c in password)
    common_patterns = ["password","123456789","987654321","hello", "goodmorning", "letmein", "food", "planes", "eat", "donuts"]
    repeating_patterns = ["abc","123","qwerty","111","aaa","xyz"]
    all_patterns = common_patterns + repeating_patterns
    inappropriate_patterns = ["f_bomb","hitler","nazism","communism"]
    has_common = any(c in password.lower()for c in all_patterns)
    not_allowed = any(c in password.lower() for c in inappropriate_patterns)

    strength_score = int(is_long_enough) + int(has_uppercase) + int(has_lowercase) + int(has_numbers) + int(has_special)
    if not_allowed:
        strength_rating = "Not Allowed"
    elif has_common:
        strength_rating = "Weak"
    elif strength_score <= 2:
        strength_rating = "Weak" 
    elif strength_score <= 3:
        strength_rating = "Medium"
    else:
        strength_rating = "Strong"

    suggestions = []
    if not is_long_enough:
        suggestions.append(f"Make password longer (at least {min_length} characters)")
    if not has_uppercase:
        suggestions.append("Add uppercase letters")
    if not has_lowercase:
        suggestions.append("Add lowercase letters")
    if not has_numbers:
        suggestions.append("Add numbers")
    if not has_special:
        suggestions.append(f"Add special characters: {special_chars}")
    if has_common:
        suggestions.append("Avoid common words or patterns")
    if not_allowed: 
        suggestions.append("Avoid inappropriate words or patterns")

    return {
        "password": password,
        "length": password_length,
        "is_long_enough": is_long_enough,
        "has_uppercase": has_uppercase,
        "has_lowercase": has_lowercase,
        "has_numbers": has_numbers,
        "has_special": has_special,
        "score": strength_score,
        "rating": strength_rating,
        "suggestions": suggestions,
        "has_common_patterns": has_common,
        "has_inappropriate_patterns": not_allowed
    }


def print_analysis(result: dict, hide_password: bool = False):
    pw = result["password"] if not hide_password else ("*" * result["length"])
    print(f"\nPassword: {pw}")
    print(f"Length: {result['length']} characters")
    print(f"Strength Score: {result['score']}/5 - {result['rating']}")
    print("Requirements met:")
    print(f"  Length >= 8: {result['is_long_enough']}")
    print(f"  Has uppercase: {result['has_uppercase']}")
    print(f"  Has lowercase: {result['has_lowercase']}")
    print(f"  Has numbers: {result['has_numbers']}")
    print(f"  Has special chars: {result['has_special']}")
    if result["suggestions"]:
        print("Suggestions for improvement:")
        for s in result["suggestions"]:
            print(f"  • {s}")
    else:
        print("🎉 Excellent! Your password meets all security requirements!")

_example_passwords = [
    "adolfhitler123",
    "David123456789",
    "987654321",
    "zacfsd",
    "Berna@3#56",
    "Wakers!",
    "Doors&Rooms2",
    "Debuggers20252026",
]

print("\nRunning examples:")
for p in _example_passwords:
    print_analysis(analyze_password(p), hide_password=False)

try:
    use_input = input("\nTry your own password? (y/N) ").strip().lower()
except Exception:
    use_input = "n"
if use_input in {"y","yes"}:
    try:
        password = input("What is your password? ")
        print_analysis(analyze_password(password), hide_password=False)
    except Exception:
        print("Interactive input not available in this environment.")
=== Password Strength Analyzer ===

Running examples:

Password: adolfhitler123
Length: 14 characters
Strength Score: 3/5 - Not Allowed
Requirements met:
  Length >= 8: True
  Has uppercase: False
  Has lowercase: True
  Has numbers: True
  Has special chars: False
Suggestions for improvement:
  • Add uppercase letters
  • Add special characters: !@#$%^&*
  • Avoid common words or patterns
  • Avoid inappropriate words or patterns

Password: David123456789
Length: 14 characters
Strength Score: 4/5 - Weak
Requirements met:
  Length >= 8: True
  Has uppercase: True
  Has lowercase: True
  Has numbers: True
  Has special chars: False
Suggestions for improvement:
  • Add special characters: !@#$%^&*
  • Avoid common words or patterns

Password: 987654321
Length: 9 characters
Strength Score: 2/5 - Weak
Requirements met:
  Length >= 8: True
  Has uppercase: False
  Has lowercase: False
  Has numbers: True
  Has special chars: False
Suggestions for improvement:
  • Add uppercase letters
  • Add lowercase letters
  • Add special characters: !@#$%^&*
  • Avoid common words or patterns

Password: zacfsd
Length: 6 characters
Strength Score: 1/5 - Weak
Requirements met:
  Length >= 8: False
  Has uppercase: False
  Has lowercase: True
  Has numbers: False
  Has special chars: False
Suggestions for improvement:
  • Make password longer (at least 8 characters)
  • Add uppercase letters
  • Add numbers
  • Add special characters: !@#$%^&*

Password: Berna@3#56
Length: 10 characters
Strength Score: 5/5 - Strong
Requirements met:
  Length >= 8: True
  Has uppercase: True
  Has lowercase: True
  Has numbers: True
  Has special chars: True
🎉 Excellent! Your password meets all security requirements!

Password: Wakers!
Length: 7 characters
Strength Score: 3/5 - Medium
Requirements met:
  Length >= 8: False
  Has uppercase: True
  Has lowercase: True
  Has numbers: False
  Has special chars: True
Suggestions for improvement:
  • Make password longer (at least 8 characters)
  • Add numbers

Password: Doors&Rooms2
Length: 12 characters
Strength Score: 5/5 - Strong
Requirements met:
  Length >= 8: True
  Has uppercase: True
  Has lowercase: True
  Has numbers: True
  Has special chars: True
🎉 Excellent! Your password meets all security requirements!

Password: Debuggers20252026
Length: 17 characters
Strength Score: 4/5 - Strong
Requirements met:
  Length >= 8: True
  Has uppercase: True
  Has lowercase: True
  Has numbers: True
  Has special chars: False
Suggestions for improvement:
  • Add special characters: !@#$%^&*