Text data often needs cleaning, parsing, and transformation before use. Python strings have built-in methods for splitting CSV data, removing whitespace, validating user input, and searching for patterns. These methods form the foundation of text processing in Python.

Python strings have many built-in methods for common text operations. These methods create new strings (strings are immutable) and cover splitting, joining, searching, replacing, and validation.

Splitting and Joining

text
split_join.py
Replay: real traced execution (multi-file project)
# Split and join


# Split string into list
text = "apple,banana,cherry,date"
fruits = text.split(",")
print("Split by comma:", fruits)

sentence = "The quick brown fox"
words = sentence.split()  # Default: split by whitespace
print("Split by space:", words)

multiline = "Line1\nLine2\nLine3"
lines = multiline.split("\n")
print("Split by newline:", lines)

# Split with limit
data = "a:b:c:d:e"
parts = data.split(":", 2)  # Split into max 3 parts
print("Limited split:", parts)

# Join list into string
# Join with separator
fruits_joined = ", ".join(fruits)
print("\nJoined:", fruits_joined)

# Join with different separator
path = "/".join(["home", "user", "documents", "file.txt"])
print("Path:", path)

# Join words with space
words_joined = " ".join(words)
print("Sentence:", words_joined)

# Join empty separator
chars = ["H", "e", "l", "l", "o"]
word = "".join(chars)
print("Word:", word)

# Split and join


# Split string into list
text = "red,green,blue"
fruits = text.split(",")
print("Split by comma:", fruits)

sentence = "The quick brown fox"
words = sentence.split()  # Default: split by whitespace
print("Split by space:", words)

multiline = "Line1\nLine2\nLine3"
lines = multiline.split("\n")
print("Split by newline:", lines)

# Split with limit
data = "a:b:c:d:e"
parts = data.split(":", 2)  # Split into max 3 parts
print("Limited split:", parts)

# Join list into string
# Join with separator
fruits_joined = ", ".join(fruits)
print("\nJoined:", fruits_joined)

# Join with different separator
path = "/".join(["home", "user", "documents", "file.txt"])
print("Path:", path)

# Join words with space
words_joined = " ".join(words)
print("Sentence:", words_joined)

# Join empty separator
chars = ["H", "e", "l", "l", "o"]
word = "".join(chars)
print("Word:", word)

# Split and join


# Split string into list
text = "cat,dog,bird"
fruits = text.split(",")
print("Split by comma:", fruits)

sentence = "The quick brown fox"
words = sentence.split()  # Default: split by whitespace
print("Split by space:", words)

multiline = "Line1\nLine2\nLine3"
lines = multiline.split("\n")
print("Split by newline:", lines)

# Split with limit
data = "a:b:c:d:e"
parts = data.split(":", 2)  # Split into max 3 parts
print("Limited split:", parts)

# Join list into string
# Join with separator
fruits_joined = ", ".join(fruits)
print("\nJoined:", fruits_joined)

# Join with different separator
path = "/".join(["home", "user", "documents", "file.txt"])
print("Path:", path)

# Join words with space
words_joined = " ".join(words)
print("Sentence:", words_joined)

# Join empty separator
chars = ["H", "e", "l", "l", "o"]
word = "".join(chars)
print("Word:", word)

  1. text ← apple,banana,cherry,date, fruits ← ['apple', 'banana', 'cherry', 'date']

    4# Split string into list5text→ apple,banana,cherry,date = "apple,banana,cherry,date"6#@text="red,green,blue", "cat,dog,bird"7fruits→ ['apple', 'banana', 'cherry', 'date'] = textapple,banana,cherry,date.split(",")8print("Split by comma:", fruits['apple', 'banana', 'cherry', 'date'])910sentence→ The quick brown fox = "The quick brown fox"11words→ ['The', 'quick', 'brown', 'fox'] = sentenceThe quick brown fox.split()  # Default: split by whitespace12print("Split by space:", words['The', 'quick', 'brown', 'fox'])1314multiline→ Line1
    Line2
    Line3 = "Line1\nLine2\nLine3"15lines→ ['Line1', 'Line2', 'Line3'] = multilineLine1
    Line2
    Line3.split("\n")16print("Split by newline:", lines['Line1', 'Line2', 'Line3'])1718# Split with limit19data→ a:b:c:d:e = "a:b:c:d:e"20parts→ ['a', 'b', 'c:d:e'] = dataa:b:c:d:e.split(":", 2)  # Split into max 3 parts21print("Limited split:", parts['a', 'b', 'c:d:e'])2223# Join list into string24# Join with separator25fruits_joined→ apple, banana, cherry, date = ", ".join(fruits['apple', 'banana', 'cherry', 'date'])26print("\nJoined:", fruits_joinedapple, banana, cherry, date)2728# Join with different separator29path→ home/user/documents/file.txt = "/".join(["home", "user", "documents", "file.txt"])30print("Path:", pathhome/user/documents/file.txt)3132# Join words with space33words_joined→ The quick brown fox = " ".join(words['The', 'quick', 'brown', 'fox'])34print("Sentence:", words_joinedThe quick brown fox)3536# Join empty separator37chars→ ['H', 'e', 'l', 'l', 'o'] = ["H", "e", "l", "l", "o"]38word→ Hello = "".join(chars['H', 'e', 'l', 'l', 'o'])39print("Word:", wordHello)
    outputSplit by comma: ['apple', 'banana', 'cherry', 'date']
    Split by space: ['The', 'quick', 'brown', 'fox']
    Split by newline: ['Line1', 'Line2', 'Line3']
    Limited split: ['a', 'b', 'c:d:e']
    
    Joined: apple, banana, cherry, date
    Path: home/user/documents/file.txt
    Sentence: The quick brown fox
    Word: Hello
  1. text ← red,green,blue, fruits ← ['red', 'green', 'blue'], sentence ← The quick brown fox

    4# Split string into list5text→ red,green,blue = "red,green,blue"6fruits→ ['red', 'green', 'blue'] = textred,green,blue.split(",")7print("Split by comma:", fruits['red', 'green', 'blue'])89sentence→ The quick brown fox = "The quick brown fox"10words→ ['The', 'quick', 'brown', 'fox'] = sentenceThe quick brown fox.split()  # Default: split by whitespace11print("Split by space:", words['The', 'quick', 'brown', 'fox'])1213multiline→ Line1
    Line2
    Line3 = "Line1\nLine2\nLine3"14lines→ ['Line1', 'Line2', 'Line3'] = multilineLine1
    Line2
    Line3.split("\n")15print("Split by newline:", lines['Line1', 'Line2', 'Line3'])1617# Split with limit18data→ a:b:c:d:e = "a:b:c:d:e"19parts→ ['a', 'b', 'c:d:e'] = dataa:b:c:d:e.split(":", 2)  # Split into max 3 parts20print("Limited split:", parts['a', 'b', 'c:d:e'])2122# Join list into string23# Join with separator24fruits_joined→ red, green, blue = ", ".join(fruits['red', 'green', 'blue'])25print("\nJoined:", fruits_joinedred, green, blue)2627# Join with different separator28path→ home/user/documents/file.txt = "/".join(["home", "user", "documents", "file.txt"])29print("Path:", pathhome/user/documents/file.txt)3031# Join words with space32words_joined→ The quick brown fox = " ".join(words['The', 'quick', 'brown', 'fox'])33print("Sentence:", words_joinedThe quick brown fox)3435# Join empty separator36chars→ ['H', 'e', 'l', 'l', 'o'] = ["H", "e", "l", "l", "o"]37word→ Hello = "".join(chars['H', 'e', 'l', 'l', 'o'])38print("Word:", wordHello)
    outputSplit by comma: ['red', 'green', 'blue']
    Split by space: ['The', 'quick', 'brown', 'fox']
    Split by newline: ['Line1', 'Line2', 'Line3']
    Limited split: ['a', 'b', 'c:d:e']
    
    Joined: red, green, blue
    Path: home/user/documents/file.txt
    Sentence: The quick brown fox
    Word: Hello
  1. text ← cat,dog,bird, fruits ← ['cat', 'dog', 'bird'], sentence ← The quick brown fox

    4# Split string into list5text→ cat,dog,bird = "cat,dog,bird"6fruits→ ['cat', 'dog', 'bird'] = textcat,dog,bird.split(",")7print("Split by comma:", fruits['cat', 'dog', 'bird'])89sentence→ The quick brown fox = "The quick brown fox"10words→ ['The', 'quick', 'brown', 'fox'] = sentenceThe quick brown fox.split()  # Default: split by whitespace11print("Split by space:", words['The', 'quick', 'brown', 'fox'])1213multiline→ Line1
    Line2
    Line3 = "Line1\nLine2\nLine3"14lines→ ['Line1', 'Line2', 'Line3'] = multilineLine1
    Line2
    Line3.split("\n")15print("Split by newline:", lines['Line1', 'Line2', 'Line3'])1617# Split with limit18data→ a:b:c:d:e = "a:b:c:d:e"19parts→ ['a', 'b', 'c:d:e'] = dataa:b:c:d:e.split(":", 2)  # Split into max 3 parts20print("Limited split:", parts['a', 'b', 'c:d:e'])2122# Join list into string23# Join with separator24fruits_joined→ cat, dog, bird = ", ".join(fruits['cat', 'dog', 'bird'])25print("\nJoined:", fruits_joinedcat, dog, bird)2627# Join with different separator28path→ home/user/documents/file.txt = "/".join(["home", "user", "documents", "file.txt"])29print("Path:", pathhome/user/documents/file.txt)3031# Join words with space32words_joined→ The quick brown fox = " ".join(words['The', 'quick', 'brown', 'fox'])33print("Sentence:", words_joinedThe quick brown fox)3435# Join empty separator36chars→ ['H', 'e', 'l', 'l', 'o'] = ["H", "e", "l", "l", "o"]37word→ Hello = "".join(chars['H', 'e', 'l', 'l', 'o'])38print("Word:", wordHello)
    outputSplit by comma: ['cat', 'dog', 'bird']
    Split by space: ['The', 'quick', 'brown', 'fox']
    Split by newline: ['Line1', 'Line2', 'Line3']
    Limited split: ['a', 'b', 'c:d:e']
    
    Joined: cat, dog, bird
    Path: home/user/documents/file.txt
    Sentence: The quick brown fox
    Word: Hello
split_join Breaking strings into lists and combining lists into strings

Trimming and Replacing

strip_replace.py
Replay: real traced execution (multi-file project)
# Strip and replace


# Strip whitespace
text1 = "   Hello World   "
print("Original:", repr(text1))
print("strip():", repr(text1.strip()))
print("lstrip():", repr(text1.lstrip()))
print("rstrip():", repr(text1.rstrip()))

# Strip specific characters
text2 = "***Hello***"
print("\nStrip asterisks:", text2.strip("*"))

text3 = "...Hello..."
print("Strip dots:", text3.strip("."))

# Replace substring
sentence = "I love Java"
updated = sentence.replace("Java", "Python")
print("\nReplace:", updated)

# Replace all occurrences
text4 = "Hello Hello Hello"
replaced = text4.replace("Hello", "Hi")
print("Replace all:", replaced)

# Replace with count limit
text5 = "one one one one"
replaced_limit = text5.replace("one", "two", 2)
print("Replace 2:", replaced_limit)

# Remove substring (replace with empty)
text6 = "Hello, World!"
no_comma = text6.replace(",", "")
print("Remove comma:", no_comma)

# Case conversion
text = "Hello World"
print("\nUpper:", text.upper())
print("Lower:", text.lower())
print("Title:", text.title())
print("Capitalize:", text.capitalize())
print("Swapcase:", text.swapcase())

  1. text1 ← Hello World , text2 ← ***Hello***, text3 ← ...Hello...

    4# Strip whitespace5text1→    Hello World    = "   Hello World   "6print("Original:", repr(text1   Hello World   ))7print("strip():", repr(text1   Hello World   .strip()))8print("lstrip():", repr(text1   Hello World   .lstrip()))9print("rstrip():", repr(text1   Hello World   .rstrip()))1011# Strip specific characters12text2→ ***Hello*** = "***Hello***"13print("\nStrip asterisks:", text2***Hello***.strip("*"))1415text3→ ...Hello... = "...Hello..."16print("Strip dots:", text3...Hello....strip("."))1718# Replace substring19sentence→ I love Java = "I love Java"20updated→ I love Python = sentenceI love Java.replace("Java", "Python")21print("\nReplace:", updatedI love Python)2223# Replace all occurrences24text4→ Hello Hello Hello = "Hello Hello Hello"25replaced→ Hi Hi Hi = text4Hello Hello Hello.replace("Hello", "Hi")26print("Replace all:", replacedHi Hi Hi)2728# Replace with count limit29text5→ one one one one = "one one one one"30replaced_limit→ two two one one = text5one one one one.replace("one", "two", 2)31print("Replace 2:", replaced_limittwo two one one)3233# Remove substring (replace with empty)34text6→ Hello, World! = "Hello, World!"35no_comma→ Hello World! = text6Hello, World!.replace(",", "")36print("Remove comma:", no_commaHello World!)3738# Case conversion39text→ Hello World = "Hello World"40print("\nUpper:", textHello World.upper())41print("Lower:", textHello World.lower())42print("Title:", textHello World.title())43print("Capitalize:", textHello World.capitalize())44print("Swapcase:", textHello World.swapcase())
    outputOriginal: '   Hello World   '
    strip(): 'Hello World'
    lstrip(): 'Hello World   '
    rstrip(): '   Hello World'
    
    Strip asterisks: Hello
    Strip dots: Hello
    
    Replace: I love Python
    Replace all: Hi Hi Hi
    Replace 2: two two one one
    Remove comma: Hello World!
    
    Upper: HELLO WORLD
    Lower: hello world
    Title: Hello World
    Capitalize: Hello world
    Swapcase: hELLO wORLD
strip_replace Removing whitespace and substituting substrings

Searching

find_index.py
Replay: real traced execution (multi-file project)
# Find and index


# Find substring
text = "Hello World Hello"

# find() returns index or -1
pos1 = text.find("World")
print(f"find('World'): {pos1}")

pos2 = text.find("Python")
print(f"find('Python'): {pos2}")  # -1 not found

# Find from specific position
pos3 = text.find("Hello", 1)  # Start search at index 1
print(f"find('Hello', 1): {pos3}")  # Finds second occurrence

# rfind() searches from right
pos4 = text.rfind("Hello")
print(f"rfind('Hello'): {pos4}")  # Last occurrence

# Index (raises exception if not found)
try:
    pos5 = text.index("World")
    print(f"\nindex('World'): {pos5}")

    # This will raise ValueError
    pos6 = text.index("Python")
except ValueError as e:
    print(f"Error: {e}")

# Count occurrences
count1 = text.count("Hello")
print(f"\ncount('Hello'): {count1}")

count2 = text.count("o")
print(f"count('o'): {count2}")

count3 = text.count("xyz")
print(f"count('xyz'): {count3}")

# Practical: check if substring exists
email = "user@example.com"

if "@" in email and "." in email:
    print(f"\n'{email}' looks like an email")

# Using find
if email.find("@") != -1:
    at_pos = email.find("@")
    domain = email[at_pos + 1:]
    print(f"Domain: {domain}")

  1. text ← Hello World Hello, pos1 ← 6, pos2 ← -1, pos3 ← 12, pos4 ← 12

    4# Find substring5text→ Hello World Hello = "Hello World Hello"67# find() returns index or -18pos1→ 6 = textHello World Hello.find("World")9print(f"find('World'): {pos16}")1011pos2→ -1 = textHello World Hello.find("Python")12print(f"find('Python'): {pos2-1}")  # -1 not found1314# Find from specific position15pos3→ 12 = textHello World Hello.find("Hello", 1)  # Start search at index 116print(f"find('Hello', 1): {pos312}")  # Finds second occurrence1718# rfind() searches from right19pos4→ 12 = textHello World Hello.rfind("Hello")20print(f"rfind('Hello'): {pos412}")  # Last occurrence
    outputfind('World'): 6
    find('Python'): -1
    find('Hello', 1): 12
    rfind('Hello'): 12
  2. pos5 ← 6

    22# Index (raises exception if not found)23try:24    pos5→ 6 = textHello World Hello.index("World")25    print(f"\nindex('World'): {pos56}")2627    # This will raise ValueError28    pos6 = textHello World Hello.index("Python")29except ValueError as e:
    output
    index('World'): 6
  3. except ValueError as e:

    28    pos6 = text.index("Python")29except ValueError as e:30    print(f"Error: {esubstring not found}")
    outputError: substring not found
  4. count1 ← 2, count2 ← 3, count3 ← 0, email ← user@example.com

    32# Count occurrences33count1→ 2 = textHello World Hello.count("Hello")34print(f"\ncount('Hello'): {count12}")3536count2→ 3 = textHello World Hello.count("o")37print(f"count('o'): {count23}")3839count3→ 0 = textHello World Hello.count("xyz")40print(f"count('xyz'): {count30}")4142# Practical: check if substring exists43email→ user@example.com = "user@example.com"
    output
    count('Hello'): 2
    count('o'): 3
    count('xyz'): 0
  5. if "@" in email and "." in email:

    45if "@" in emailuser@example.com and "." in email:46    print(f"\n'{emailuser@example.com}' looks like an email")
    output
    'user@example.com' looks like an email
  6. at_pos ← 4, domain ← example.com

    48# Using find49if emailuser@example.com.find("@") != -1:50    at_pos→ 4 = emailuser@example.com.find("@")51    domain→ example.com = email[at_pos + 1:]example.com52    print(f"Domain: {domainexample.com}")
    outputDomain: example.com
find_search Finding substrings and their positions in strings

Validation

validation.py
Replay: real traced execution (multi-file project)
# String validation methods


# Digit checking
age_str = "25"
invalid_age = "25.5"

print(f"'{age_str}'.isdigit(): {age_str.isdigit()}")
print(f"'{invalid_age}'.isdigit(): {invalid_age.isdigit()}")

# Validate numeric input
inputs = ["123", "abc", "12.34", "-5", ""]

print("\nDigit validation:")
for inp in inputs:
    if inp.isdigit():
        print(f"  '{inp}' is valid positive integer")
    else:
        print(f"  '{inp}' is NOT a digit string")

# Alpha checking
name = "John"
mixed = "John123"

print(f"\n'{name}'.isalpha(): {name.isalpha()}")
print(f"'{mixed}'.isalpha(): {mixed.isalpha()}")

# Check if valid name (letters only)
names = ["Alice", "Bob123", "Charlie-", "Diana"]

print("\nValid names (letters only):")
for n in names:
    if n.isalpha():
        print(f"  {n}")

# Alphanumeric checking
username = "user123"
invalid_user = "user@123"

print(f"\n'{username}'.isalnum(): {username.isalnum()}")
print(f"'{invalid_user}'.isalnum(): {invalid_user.isalnum()}")

# Case checking
text1 = "HELLO"
text2 = "hello"
text3 = "Hello"

print(f"\n'{text1}'.isupper(): {text1.isupper()}")
print(f"'{text2}'.islower(): {text2.islower()}")
print(f"'{text3}'.istitle(): {text3.istitle()}")

# Space checking
spaces = "   "
empty = ""
text = "Hello"

print(f"\n'{spaces}'.isspace(): {spaces.isspace()}")
print(f"'{empty}'.isspace(): {empty.isspace()}")
print(f"'{text}'.isspace(): {text.isspace()}")

# Practical: validate username
def validate_username(username):
    """Validate username: 3-20 chars, alphanumeric"""
    if len(username) < 3 or len(username) > 20:
        return False, "Length must be 3-20 characters"

    if not username.isalnum():
        return False, "Only letters and numbers allowed"

    if username.isdigit():
        return False, "Cannot be all digits"

    return True, "Valid username"


test_users = ["alice", "bob123", "a", "user@name", "12345", "VeryLongUsernameThatExceedsLimit"]

print("\nUsername validation:")
for user in test_users:
    valid, message = validate_username(user)
    status = "✓" if valid else "✗"
    print(f"  {status} '{user}': {message}")

  1. age_str ← 25, invalid_age ← 25.5, inputs ← ['123', 'abc', '12.34', '-5', '']

    4# Digit checking5age_str→ 25 = "25"6invalid_age→ 25.5 = "25.5"78print(f"'{age_str25}'.isdigit(): {age_str.isdigit()}")9print(f"'{invalid_age25.5}'.isdigit(): {invalid_age.isdigit()}")1011# Validate numeric input12inputs→ ['123', 'abc', '12.34', '-5', ''] = ["123", "abc", "12.34", "-5", ""]1314print("\nDigit validation:")15for inp in inputs:
    output'25'.isdigit(): True
    '25.5'.isdigit(): False
    
    Digit validation:
  2. for inp in inputs:

    pass 1 of 5
    14print("\nDigit validation:")15for inp123 in inputs['123', 'abc', '12.34', '-5', '']:16    if inp.isdigit():17        print(f"  '{inp}' is valid positive integer")
    All 5 passes — pass 1 is the card above
    passinp
    1123
    2abc
    312.34
    4-5
    5(empty)
  3. if inp.isdigit():

    15for inp in inputs:16    if inp123.isdigit():17        print(f"  '{inp123}' is valid positive integer")18    else:
    output  '123' is valid positive integer
  4. else:

    pass 1 of 4
    16if inp.isdigit():17    print(f"  '{inp}' is valid positive integer")18else:19    print(f"  '{inpabc}' is NOT a digit string")
    output  'abc' is NOT a digit string
    All 4 passes — pass 1 is the card above
    passinp
    1abc
    212.34
    3-5
    4(empty)
  5. name ← John, mixed ← John123, names ← ['Alice', 'Bob123', 'Charlie-', 'Diana']

    21# Alpha checking22name→ John = "John"23mixed→ John123 = "John123"2425print(f"\n'{nameJohn}'.isalpha(): {name.isalpha()}")26print(f"'{mixedJohn123}'.isalpha(): {mixed.isalpha()}")2728# Check if valid name (letters only)29names→ ['Alice', 'Bob123', 'Charlie-', 'Diana'] = ["Alice", "Bob123", "Charlie-", "Diana"]3031print("\nValid names (letters only):")32for n in names:
    output
    'John'.isalpha(): True
    'John123'.isalpha(): False
    
    Valid names (letters only):
  6. for n in names:

    pass 1 of 4
    31print("\nValid names (letters only):")32for nAlice in names['Alice', 'Bob123', 'Charlie-', 'Diana']:33    if n.isalpha():34        print(f"  {n}")
    All 4 passes — pass 1 is the card above
    passn
    1Alice
    2Bob123
    3Charlie-
    4Diana
  7. if n.isalpha():

    pass 1 of 2
    32for n in names:33    if nAlice.isalpha():34        print(f"  {nAlice}")
    output  Alice
  8. if n.isalpha():

    pass 2 of 2
    32for n in names:33    if nDiana.isalpha():34        print(f"  {nDiana}")
    output  Diana
  9. username ← user123, invalid_user ← user@123, text1 ← HELLO, text2 ← hello

    36# Alphanumeric checking37username→ user123 = "user123"38invalid_user→ user@123 = "user@123"3940print(f"\n'{usernameuser123}'.isalnum(): {username.isalnum()}")41print(f"'{invalid_useruser@123}'.isalnum(): {invalid_user.isalnum()}")4243# Case checking44text1→ HELLO = "HELLO"45text2→ hello = "hello"46text3→ Hello = "Hello"4748print(f"\n'{text1HELLO}'.isupper(): {text1.isupper()}")49print(f"'{text2hello}'.islower(): {text2.islower()}")50print(f"'{text3Hello}'.istitle(): {text3.istitle()}")5152# Space checking53spaces = "   "54empty→ (empty) = ""55text→ Hello = "Hello"5657print(f"\n'{spaces   }'.isspace(): {spaces.isspace()}")58print(f"'{empty(empty)}'.isspace(): {empty.isspace()}")59print(f"'{textHello}'.isspace(): {text.isspace()}")6061# Practical: validate username62def validate_username(username):63    """Validate username: 3-20 chars, alphanumeric"""64    if len(username) < 3 or len(username) > 20:65        return False, "Length must be 3-20 characters"6667    if not username.isalnum():68        return False, "Only letters and numbers allowed"6970    if username.isdigit():71        return False, "Cannot be all digits"7273    return True, "Valid username"747576test_users→ ['alice', 'bob123', 'a', 'user@name', '12345', 'VeryLongUsernameThatExceedsLimit'] = ["alice", "bob123", "a", "user@name", "12345", "VeryLongUsernameThatExceedsLimit"]7778print("\nUsername validation:")79for user in test_users:
    output
    'user123'.isalnum(): True
    'user@123'.isalnum(): False
    
    'HELLO'.isupper(): True
    'hello'.islower(): True
    'Hello'.istitle(): True
    
    '   '.isspace(): True
    ''.isspace(): False
    'Hello'.isspace(): False
    
    Username validation:
  10. for user in test_users:

    pass 1 of 6
    78print("\nUsername validation:")79for useralice in test_users['alice', 'bob123', 'a', 'user@name', '12345', 'VeryLongUsernameThatExceedsLimit']:80    valid, message = validate_username(useralice)81    status = "✓" if valid else "✗"
    All 6 passes — pass 1 is the card above
    passuserusername
    1alice
    2bob123
    3aa
    4user@nameuser@name
    51234512345
    6VeryLongUsernameThatExceedsLimitVeryLongUsernameThatExceedsLimit
  11. def validate_username(username):

    pass 1 of 6
    61# Practical: validate username62def validate_username(usernamealice):63    """Validate username: 3-20 chars, alphanumeric"""64    if len(username) < 3 or len(username) > 20:65        return False, "Length must be 3-20 characters"6667    if not username.isalnum():68        return False, "Only letters and numbers allowed"6970    if username.isdigit():71        return False, "Cannot be all digits"7273    return True, "Valid username"
    All 6 passes — pass 1 is the card above
    passusername
    1alice
    2bob123
    3a
    4user@name
    512345
    6VeryLongUsernameThatExceedsLimit
  12. valid ← True, message ← Valid username, status ← ✓

    79for user in test_users:80    valid→ True, message→ Valid username = validate_username(useralice)81    status→ ✓ = "✓" if validTrue else "✗"82    print(f"  {status} '{useralice}': {messageValid username}")
    output  ✓ 'alice': Valid username
  13. valid ← True, message ← Valid username, status ← ✓

    79for user in test_users:80    valid→ True, message→ Valid username = validate_username(userbob123)81    status→ ✓ = "✓" if validTrue else "✗"82    print(f"  {status} '{userbob123}': {messageValid username}")
    output  ✓ 'bob123': Valid username
  14. if len(username) < 3 or len(username) > 20:

    pass 1 of 2
    63"""Validate username: 3-20 chars, alphanumeric"""64if len(usernamea) < 3 or len(username) > 20:65    return False, "Length must be 3-20 characters"
  15. valid ← False, message ← Length must be 3-20 characters, status ← ✗

    79for user in test_users:80    valid→ False, message→ Length must be 3-20 characters = validate_username(usera)81    status→ ✗ = "✓" if validFalse else "✗"82    print(f"  {status} '{usera}': {messageLength must be 3-20 characters}")
    output  ✗ 'a': Length must be 3-20 characters
  16. if not username.isalnum():

    67if not usernameuser@name.isalnum():68    return False, "Only letters and numbers allowed"
  17. valid ← False, message ← Only letters and numbers allowed, status ← ✗

    79for user in test_users:80    valid→ False, message→ Only letters and numbers allowed = validate_username(useruser@name)81    status→ ✗ = "✓" if validFalse else "✗"82    print(f"  {status} '{useruser@name}': {messageOnly letters and numbers allowed}")
    output  ✗ 'user@name': Only letters and numbers allowed
  18. if username.isdigit():

    70if username12345.isdigit():71    return False, "Cannot be all digits"
  19. valid ← False, message ← Cannot be all digits, status ← ✗

    79for user in test_users:80    valid→ False, message→ Cannot be all digits = validate_username(user12345)81    status→ ✗ = "✓" if validFalse else "✗"82    print(f"  {status} '{user12345}': {messageCannot be all digits}")
    output  ✗ '12345': Cannot be all digits
  20. if len(username) < 3 or len(username) > 20:

    pass 2 of 2
    63"""Validate username: 3-20 chars, alphanumeric"""64if len(usernameVeryLongUsernameThatExceedsLimit) < 3 or len(username) > 20:65    return False, "Length must be 3-20 characters"
  21. valid ← False, message ← Length must be 3-20 characters, status ← ✗

    79for user in test_users:80    valid→ False, message→ Length must be 3-20 characters = validate_username(userVeryLongUsernameThatExceedsLimit)81    status→ ✗ = "✓" if validFalse else "✗"82    print(f"  {status} '{userVeryLongUsernameThatExceedsLimit}': {messageLength must be 3-20 characters}")
    output  ✗ 'VeryLongUsernameThatExceedsLimit': Length must be 3-20 characters
validation Checking string content with isdigit(), isalpha(), and related methods

Prefix and Suffix Checking

startswith_endswith.py
Replay: real traced execution (multi-file project)
# Startswith and endswith


# Check prefix
filename = "document.txt"

if filename.startswith("doc"):
    print(f"'{filename}' starts with 'doc'")

if filename.startswith("image"):
    print("This won't print")
else:
    print(f"'{filename}' doesn't start with 'image'")

# Check multiple prefixes
url = "https://example.com"
if url.startswith(("http://", "https://")):
    print(f"'{url}' is a valid URL")

# Check suffix
files = ["report.pdf", "data.csv", "image.png", "script.py"]

print("\nPython files:")
for file in files:
    if file.endswith(".py"):
        print(f"  {file}")

print("\nData files:")
for file in files:
    if file.endswith((".csv", ".json", ".xml")):
        print(f"  {file}")

# Practical: file type detection
def get_file_type(filename):
    """Determine file type by extension"""
    if filename.endswith((".jpg", ".png", ".gif")):
        return "Image"
    elif filename.endswith((".txt", ".md", ".log")):
        return "Text"
    elif filename.endswith((".py", ".java", ".js")):
        return "Code"
    elif filename.endswith((".pdf", ".doc", ".docx")):
        return "Document"
    else:
        return "Unknown"


test_files = ["photo.jpg", "script.py", "README.md", "report.pdf", "data.db"]

print("\nFile types:")
for file in test_files:
    print(f"  {file}: {get_file_type(file)}")

# Remove extension
def remove_extension(filename):
    """Remove file extension"""
    if "." in filename:
        dot_pos = filename.rfind(".")
        return filename[:dot_pos]
    return filename


print("\nWithout extensions:")
for file in test_files:
    print(f"  {file} → {remove_extension(file)}")

  1. filename ← document.txt

    4# Check prefix5filename→ document.txt = "document.txt"
  2. if filename.startswith("doc"):

    7if filenamedocument.txt.startswith("doc"):8    print(f"'{filenamedocument.txt}' starts with 'doc'")
    output'document.txt' starts with 'doc'
  3. else:

    10if filename.startswith("image"):11    print("This won't print")12else:13    print(f"'{filenamedocument.txt}' doesn't start with 'image'")
    output'document.txt' doesn't start with 'image'
  4. url ← https://example.com

    15# Check multiple prefixes16url→ https://example.com = "https://example.com"17if url.startswith(("http://", "https://")):
  5. if url.startswith(("http://", "https://")):

    16url = "https://example.com"17if urlhttps://example.com.startswith(("http://", "https://")):18    print(f"'{urlhttps://example.com}' is a valid URL")
    output'https://example.com' is a valid URL
  6. files ← ['report.pdf', 'data.csv', 'image.png', 'script.py']

    20# Check suffix21files→ ['report.pdf', 'data.csv', 'image.png', 'script.py'] = ["report.pdf", "data.csv", "image.png", "script.py"]2223print("\nPython files:")24for file in files:
    output
    Python files:
  7. for file in files:

    pass 1 of 4
    23print("\nPython files:")24for filereport.pdf in files['report.pdf', 'data.csv', 'image.png', 'script.py']:25    if file.endswith(".py"):26        print(f"  {file}")
    All 4 passes — pass 1 is the card above
    passfile
    1report.pdf
    2data.csv
    3image.png
    4script.py
  8. if file.endswith(".py"):

    24for file in files:25    if filescript.py.endswith(".py"):26        print(f"  {filescript.py}")
    output  script.py
  9. print(" Data files:")

    28print("\nData files:")29for file in files:
    output
    Data files:
  10. for file in files:

    pass 1 of 4
    28print("\nData files:")29for filereport.pdf in files['report.pdf', 'data.csv', 'image.png', 'script.py']:30    if file.endswith((".csv", ".json", ".xml")):31        print(f"  {file}")
    All 4 passes — pass 1 is the card above
    passfile
    1report.pdf
    2data.csv
    3image.png
    4script.py
  11. if file.endswith((".csv", ".json", ".xml")):

    29for file in files:30    if filedata.csv.endswith((".csv", ".json", ".xml")):31        print(f"  {filedata.csv}")
    output  data.csv
  12. test_files ← ['photo.jpg', 'script.py', 'README.md', 'report.pdf', 'data.db']

    48test_files→ ['photo.jpg', 'script.py', 'README.md', 'report.pdf', 'data.db'] = ["photo.jpg", "script.py", "README.md", "report.pdf", "data.db"]4950print("\nFile types:")51for file in test_files:
    output
    File types:
  13. for file in test_files:

    pass 1 of 5
    50print("\nFile types:")51for filephoto.jpg in test_files['photo.jpg', 'script.py', 'README.md', 'report.pdf', 'data.db']:52    print(f"  {filephoto.jpg}: {get_file_type(file)}")
    All 5 passes — pass 1 is the card above
    passfilefilename
    1photo.jpgphoto.jpg
    2script.pyscript.py
    3README.mdREADME.md
    4report.pdfreport.pdf
    5data.db
  14. def get_file_type(filename):

    pass 1 of 5
    33# Practical: file type detection34def get_file_type(filenamephoto.jpg):35    """Determine file type by extension"""36    if filename.endswith((".jpg", ".png", ".gif")):
    All 5 passes — pass 1 is the card above
    passfilename
    1photo.jpg
    2script.py
    3README.md
    4report.pdf
    5data.db
  15. if filename.endswith((".jpg", ".png", ".gif")):

    35"""Determine file type by extension"""36if filenamephoto.jpg.endswith((".jpg", ".png", ".gif")):37    return "Image"38elif filename.endswith((".txt", ".md", ".log")):
  16. print(f" {file}: {get_file_type(file)}")

    51for file in test_files:52    print(f"  {filephoto.jpg}: {get_file_type(file)}")
    output  photo.jpg: Image
  17. elif filename.endswith((".py", ".java", ".js")):

    39    return "Text"40elif filenamescript.py.endswith((".py", ".java", ".js")):41    return "Code"42elif filename.endswith((".pdf", ".doc", ".docx")):
  18. print(f" {file}: {get_file_type(file)}")

    51for file in test_files:52    print(f"  {filescript.py}: {get_file_type(file)}")
    output  script.py: Code
  19. elif filename.endswith((".txt", ".md", ".log")):

    37    return "Image"38elif filenameREADME.md.endswith((".txt", ".md", ".log")):39    return "Text"40elif filename.endswith((".py", ".java", ".js")):
  20. print(f" {file}: {get_file_type(file)}")

    51for file in test_files:52    print(f"  {fileREADME.md}: {get_file_type(file)}")
    output  README.md: Text
  21. elif filename.endswith((".pdf", ".doc", ".docx")):

    41    return "Code"42elif filenamereport.pdf.endswith((".pdf", ".doc", ".docx")):43    return "Document"44else:
  22. print(f" {file}: {get_file_type(file)}")

    51for file in test_files:52    print(f"  {filereport.pdf}: {get_file_type(file)}")
    output  report.pdf: Document
  23. print(f" {file}: {get_file_type(file)}")

    51for file in test_files:52    print(f"  {filedata.db}: {get_file_type(file)}")
    output  data.db: Unknown
  24. print(" Without extensions:")

    63print("\nWithout extensions:")64for file in test_files:
    output
    Without extensions:
  25. for file in test_files:

    pass 1 of 5
    63print("\nWithout extensions:")64for filephoto.jpg in test_files['photo.jpg', 'script.py', 'README.md', 'report.pdf', 'data.db']:65    print(f"  {filephoto.jpg} → {remove_extension(file)}")
    All 5 passes — pass 1 is the card above
    passfile
    1photo.jpg
    2script.py
    3README.md
    4report.pdf
    5data.db
  26. def remove_extension(filename):

    pass 1 of 5
    54# Remove extension55def remove_extension(filenamephoto.jpg):56    """Remove file extension"""57    if "." in filename:
    All 5 passes — pass 1 is the card above
    passfilename
    1photo.jpg
    2script.py
    3README.md
    4report.pdf
    5data.db
  27. dot_pos ← 5

    pass 1 of 5
    56"""Remove file extension"""57if "." in filenamephoto.jpg:58    dot_pos→ 5 = filenamephoto.jpg.rfind(".")59    return filename[:dot_pos]photo60return filename
    All 5 passes — pass 1 is the card above
    passfilenamefilename[:dot_pos]dot_pos
    1photo.jpgphoto5
    2script.pyscript6
    3README.mdREADME6
    4report.pdfreport6
    5data.dbdata4
  28. print(f" {file} → {remove_extension(file)}")

    64for file in test_files:65    print(f"  {filephoto.jpg} → {remove_extension(file)}")
    output  photo.jpg → photo
  29. print(f" {file} → {remove_extension(file)}")

    64for file in test_files:65    print(f"  {filescript.py} → {remove_extension(file)}")
    output  script.py → script
  30. print(f" {file} → {remove_extension(file)}")

    64for file in test_files:65    print(f"  {fileREADME.md} → {remove_extension(file)}")
    output  README.md → README
  31. print(f" {file} → {remove_extension(file)}")

    64for file in test_files:65    print(f"  {filereport.pdf} → {remove_extension(file)}")
    output  report.pdf → report
  32. print(f" {file} → {remove_extension(file)}")

    64for file in test_files:65    print(f"  {filedata.db} → {remove_extension(file)}")
    output  data.db → data
prefix_suffix Checking if strings start or end with specific substrings

Characteristics

  • Immutable: Methods return new strings
  • Chainable: Can chain method calls
  • Unicode-aware: Work with international text
  • Many methods: Rich standard library

Exercise: practical.py

Build a text processing pipeline that cleans user input, parses CSV data, and formats phone numbers