String Processing
String Methods
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
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)
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
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
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())
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}")
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 occurrenceoutputfind('World'): 6 find('Python'): -1 find('Hello', 1): 12 rfind('Hello'): 12pos5 ← 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'): 6except ValueError as e:
28 pos6 = text.index("Python")29except ValueError as e:30 print(f"Error: {esubstring not found}")outputError: substring not foundcount1 ← 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'): 0if "@" 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 emailat_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}")
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:for inp in inputs:
pass 1 of 514print("\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 pass inp1 123 2 abc 3 12.34 4 -5 5 (empty) 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 integerelse:
pass 1 of 416if 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 stringAll 4 passes — pass 1 is the card above pass inp1 abc 2 12.34 3 -5 4 (empty) 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):for n in names:
pass 1 of 431print("\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 pass n1 Alice 2 Bob123 3 Charlie- 4 Diana if n.isalpha():
pass 1 of 232for n in names:33 if nAlice.isalpha():34 print(f" {nAlice}")output Aliceif n.isalpha():
pass 2 of 232for n in names:33 if nDiana.isalpha():34 print(f" {nDiana}")output Dianausername ← 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:for user in test_users:
pass 1 of 678print("\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 pass userusername1 alice — 2 bob123 — 3 a a 4 user@name user@name 5 12345 12345 6 VeryLongUsernameThatExceedsLimit VeryLongUsernameThatExceedsLimit def validate_username(username):
pass 1 of 661# 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 pass username1 alice 2 bob123 3 a 4 user@name 5 12345 6 VeryLongUsernameThatExceedsLimit 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 usernamevalid ← 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 usernameif len(username) < 3 or len(username) > 20:
pass 1 of 263"""Validate username: 3-20 chars, alphanumeric"""64if len(usernamea) < 3 or len(username) > 20:65 return False, "Length must be 3-20 characters"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 charactersif not username.isalnum():
67if not usernameuser@name.isalnum():68 return False, "Only letters and numbers allowed"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 allowedif username.isdigit():
70if username12345.isdigit():71 return False, "Cannot be all digits"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 digitsif len(username) < 3 or len(username) > 20:
pass 2 of 263"""Validate username: 3-20 chars, alphanumeric"""64if len(usernameVeryLongUsernameThatExceedsLimit) < 3 or len(username) > 20:65 return False, "Length must be 3-20 characters"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)}")
filename ← document.txt
4# Check prefix5filename→ document.txt = "document.txt"if filename.startswith("doc"):
7if filenamedocument.txt.startswith("doc"):8 print(f"'{filenamedocument.txt}' starts with 'doc'")output'document.txt' starts with 'doc'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'url ← https://example.com
15# Check multiple prefixes16url→ https://example.com = "https://example.com"17if url.startswith(("http://", "https://")):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 URLfiles ← ['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:for file in files:
pass 1 of 423print("\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 pass file1 report.pdf 2 data.csv 3 image.png 4 script.py if file.endswith(".py"):
24for file in files:25 if filescript.py.endswith(".py"):26 print(f" {filescript.py}")output script.pyprint(" Data files:")
28print("\nData files:")29for file in files:output Data files:for file in files:
pass 1 of 428print("\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 pass file1 report.pdf 2 data.csv 3 image.png 4 script.py 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.csvtest_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:for file in test_files:
pass 1 of 550print("\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 pass filefilename1 photo.jpg photo.jpg 2 script.py script.py 3 README.md README.md 4 report.pdf report.pdf 5 data.db — def get_file_type(filename):
pass 1 of 533# 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 pass filename1 photo.jpg 2 script.py 3 README.md 4 report.pdf 5 data.db 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")):print(f" {file}: {get_file_type(file)}")
51for file in test_files:52 print(f" {filephoto.jpg}: {get_file_type(file)}")output photo.jpg: Imageelif filename.endswith((".py", ".java", ".js")):
39 return "Text"40elif filenamescript.py.endswith((".py", ".java", ".js")):41 return "Code"42elif filename.endswith((".pdf", ".doc", ".docx")):print(f" {file}: {get_file_type(file)}")
51for file in test_files:52 print(f" {filescript.py}: {get_file_type(file)}")output script.py: Codeelif filename.endswith((".txt", ".md", ".log")):
37 return "Image"38elif filenameREADME.md.endswith((".txt", ".md", ".log")):39 return "Text"40elif filename.endswith((".py", ".java", ".js")):print(f" {file}: {get_file_type(file)}")
51for file in test_files:52 print(f" {fileREADME.md}: {get_file_type(file)}")output README.md: Textelif filename.endswith((".pdf", ".doc", ".docx")):
41 return "Code"42elif filenamereport.pdf.endswith((".pdf", ".doc", ".docx")):43 return "Document"44else:print(f" {file}: {get_file_type(file)}")
51for file in test_files:52 print(f" {filereport.pdf}: {get_file_type(file)}")output report.pdf: Documentprint(f" {file}: {get_file_type(file)}")
51for file in test_files:52 print(f" {filedata.db}: {get_file_type(file)}")output data.db: Unknownprint(" Without extensions:")
63print("\nWithout extensions:")64for file in test_files:output Without extensions:for file in test_files:
pass 1 of 563print("\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 pass file1 photo.jpg 2 script.py 3 README.md 4 report.pdf 5 data.db def remove_extension(filename):
pass 1 of 554# Remove extension55def remove_extension(filenamephoto.jpg):56 """Remove file extension"""57 if "." in filename:All 5 passes — pass 1 is the card above pass filename1 photo.jpg 2 script.py 3 README.md 4 report.pdf 5 data.db dot_pos ← 5
pass 1 of 556"""Remove file extension"""57if "." in filenamephoto.jpg:58 dot_pos→ 5 = filenamephoto.jpg.rfind(".")59 return filename[:dot_pos]photo60return filenameAll 5 passes — pass 1 is the card above pass filenamefilename[:dot_pos]dot_pos1 photo.jpg photo 5 2 script.py script 6 3 README.md README 6 4 report.pdf report 6 5 data.db data 4 print(f" {file} → {remove_extension(file)}")
64for file in test_files:65 print(f" {filephoto.jpg} → {remove_extension(file)}")output photo.jpg → photoprint(f" {file} → {remove_extension(file)}")
64for file in test_files:65 print(f" {filescript.py} → {remove_extension(file)}")output script.py → scriptprint(f" {file} → {remove_extension(file)}")
64for file in test_files:65 print(f" {fileREADME.md} → {remove_extension(file)}")output README.md → READMEprint(f" {file} → {remove_extension(file)}")
64for file in test_files:65 print(f" {filereport.pdf} → {remove_extension(file)}")output report.pdf → reportprint(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