A user submits a search query: " PIZZA ". Before searching, you need to clean it up (strip spaces), normalize it (lowercase), then search your database. String operations make this possible.

Change case (normalize input)

Convert text to uppercase or lowercase for consistent comparisons.

example
case.py
Replay: real traced execution (multi-file project)
text = "Hello World"

upper = text.upper()
lower = text.lower()
title = text.title()
capitalize = text.capitalize()

print(f"Original:   {text}")
print(f"Upper:      {upper}")
print(f"Lower:      {lower}")
print(f"Title:      {title}")
print(f"Capitalize: {capitalize}")

# Practical: case-insensitive comparison
user_answer = "YES"
if user_answer.lower() == "yes":
    print("User agreed (any case)")
text = "PYTHON programming"

upper = text.upper()
lower = text.lower()
title = text.title()
capitalize = text.capitalize()

print(f"Original:   {text}")
print(f"Upper:      {upper}")
print(f"Lower:      {lower}")
print(f"Title:      {title}")
print(f"Capitalize: {capitalize}")

# Practical: case-insensitive comparison
user_answer = "YES"
if user_answer.lower() == "yes":
    print("User agreed (any case)")
text = "PyThOn"

upper = text.upper()
lower = text.lower()
title = text.title()
capitalize = text.capitalize()

print(f"Original:   {text}")
print(f"Upper:      {upper}")
print(f"Lower:      {lower}")
print(f"Title:      {title}")
print(f"Capitalize: {capitalize}")

# Practical: case-insensitive comparison
user_answer = "YES"
if user_answer.lower() == "yes":
    print("User agreed (any case)")
text = "Hello World"

upper = text.upper()
lower = text.lower()
title = text.title()
capitalize = text.capitalize()

print(f"Original:   {text}")
print(f"Upper:      {upper}")
print(f"Lower:      {lower}")
print(f"Title:      {title}")
print(f"Capitalize: {capitalize}")

# Practical: case-insensitive comparison
user_answer = "yes"
if user_answer.lower() == "yes":
    print("User agreed (any case)")
text = "Hello World"

upper = text.upper()
lower = text.lower()
title = text.title()
capitalize = text.capitalize()

print(f"Original:   {text}")
print(f"Upper:      {upper}")
print(f"Lower:      {lower}")
print(f"Title:      {title}")
print(f"Capitalize: {capitalize}")

# Practical: case-insensitive comparison
user_answer = "Yes"
if user_answer.lower() == "yes":
    print("User agreed (any case)")
  1. text ← Hello World, upper ← HELLO WORLD, lower ← hello world, title ← Hello World

    1text→ Hello World = "Hello World"  #@text="PYTHON programming", "PyThOn"23upper→ HELLO WORLD = textHello World.upper()4lower→ hello world = textHello World.lower()5title→ Hello World = textHello World.title()6capitalize→ Hello world = textHello World.capitalize()78print(f"Original:   {textHello World}")9print(f"Upper:      {upperHELLO WORLD}")10print(f"Lower:      {lowerhello world}")11print(f"Title:      {titleHello World}")12print(f"Capitalize: {capitalizeHello world}")1314# Practical: case-insensitive comparison15user_answer→ YES = "YES"  #@user_answer="yes", "Yes"16if user_answer.lower() == "yes":
    outputOriginal:   Hello World
    Upper:      HELLO WORLD
    Lower:      hello world
    Title:      Hello World
    Capitalize: Hello world
  2. if user_answer.lower() == "yes":

    15user_answer = "YES"  #@user_answer="yes", "Yes"16if user_answerYES.lower() == "yes":17    print("User agreed (any case)")
    outputUser agreed (any case)
  1. text ← PYTHON programming, upper ← PYTHON PROGRAMMING, lower ← python programming

    1text→ PYTHON programming = "PYTHON programming"23upper→ PYTHON PROGRAMMING = textPYTHON programming.upper()4lower→ python programming = textPYTHON programming.lower()5title→ Python Programming = textPYTHON programming.title()6capitalize→ Python programming = textPYTHON programming.capitalize()78print(f"Original:   {textPYTHON programming}")9print(f"Upper:      {upperPYTHON PROGRAMMING}")10print(f"Lower:      {lowerpython programming}")11print(f"Title:      {titlePython Programming}")12print(f"Capitalize: {capitalizePython programming}")1314# Practical: case-insensitive comparison15user_answer→ YES = "YES"16if user_answer.lower() == "yes":
    outputOriginal:   PYTHON programming
    Upper:      PYTHON PROGRAMMING
    Lower:      python programming
    Title:      Python Programming
    Capitalize: Python programming
  2. if user_answer.lower() == "yes":

    15user_answer = "YES"16if user_answerYES.lower() == "yes":17    print("User agreed (any case)")
    outputUser agreed (any case)
  1. text ← PyThOn, upper ← PYTHON, lower ← python, title ← Python

    1text→ PyThOn = "PyThOn"23upper→ PYTHON = textPyThOn.upper()4lower→ python = textPyThOn.lower()5title→ Python = textPyThOn.title()6capitalize→ Python = textPyThOn.capitalize()78print(f"Original:   {textPyThOn}")9print(f"Upper:      {upperPYTHON}")10print(f"Lower:      {lowerpython}")11print(f"Title:      {titlePython}")12print(f"Capitalize: {capitalizePython}")1314# Practical: case-insensitive comparison15user_answer→ YES = "YES"16if user_answer.lower() == "yes":
    outputOriginal:   PyThOn
    Upper:      PYTHON
    Lower:      python
    Title:      Python
    Capitalize: Python
  2. if user_answer.lower() == "yes":

    15user_answer = "YES"16if user_answerYES.lower() == "yes":17    print("User agreed (any case)")
    outputUser agreed (any case)
  1. text ← Hello World, upper ← HELLO WORLD, lower ← hello world, title ← Hello World

    1text→ Hello World = "Hello World"23upper→ HELLO WORLD = textHello World.upper()4lower→ hello world = textHello World.lower()5title→ Hello World = textHello World.title()6capitalize→ Hello world = textHello World.capitalize()78print(f"Original:   {textHello World}")9print(f"Upper:      {upperHELLO WORLD}")10print(f"Lower:      {lowerhello world}")11print(f"Title:      {titleHello World}")12print(f"Capitalize: {capitalizeHello world}")1314# Practical: case-insensitive comparison15user_answer→ yes = "yes"16if user_answer.lower() == "yes":
    outputOriginal:   Hello World
    Upper:      HELLO WORLD
    Lower:      hello world
    Title:      Hello World
    Capitalize: Hello world
  2. if user_answer.lower() == "yes":

    15user_answer = "yes"16if user_answeryes.lower() == "yes":17    print("User agreed (any case)")
    outputUser agreed (any case)
  1. text ← Hello World, upper ← HELLO WORLD, lower ← hello world, title ← Hello World

    1text→ Hello World = "Hello World"23upper→ HELLO WORLD = textHello World.upper()4lower→ hello world = textHello World.lower()5title→ Hello World = textHello World.title()6capitalize→ Hello world = textHello World.capitalize()78print(f"Original:   {textHello World}")9print(f"Upper:      {upperHELLO WORLD}")10print(f"Lower:      {lowerhello world}")11print(f"Title:      {titleHello World}")12print(f"Capitalize: {capitalizeHello world}")1314# Practical: case-insensitive comparison15user_answer→ Yes = "Yes"16if user_answer.lower() == "yes":
    outputOriginal:   Hello World
    Upper:      HELLO WORLD
    Lower:      hello world
    Title:      Hello World
    Capitalize: Hello world
  2. if user_answer.lower() == "yes":

    15user_answer = "Yes"16if user_answerYes.lower() == "yes":17    print("User agreed (any case)")
    outputUser agreed (any case)

Normalize input before comparing - users might type "YES", "Yes", or "yes".

upper/lower Change case: `"Hello".upper()` → `"HELLO"`, `"Hello".lower()` → `"hello"`

Strip whitespace (clean input)

Remove extra spaces from the beginning and end of user input.

tabbed
strip.py
Replay: real traced execution (multi-file project)
messy_input = "   Alice Smith   "
clean = messy_input.strip()

print(f"With spaces: '{messy_input}'")
print(f"Stripped:    '{clean}'")
print(f"Length before: {len(messy_input)}")
print(f"Length after:  {len(clean)}")

# Different strip variants
tabbed = "\t  data  \n"
print(f"strip():  '{tabbed.strip()}'")
print(f"lstrip(): '{tabbed.lstrip()}'")  # left only
print(f"rstrip(): '{tabbed.rstrip()}'")  # right only

# Strip specific characters
dashes = "---hello---"
print(f"strip('-'): '{dashes.strip('-')}'")
messy_input = "   Alice Smith   "
clean = messy_input.strip()

print(f"With spaces: '{messy_input}'")
print(f"Stripped:    '{clean}'")
print(f"Length before: {len(messy_input)}")
print(f"Length after:  {len(clean)}")

# Different strip variants
tabbed = "\t\tmore\t\t"
print(f"strip():  '{tabbed.strip()}'")
print(f"lstrip(): '{tabbed.lstrip()}'")  # left only
print(f"rstrip(): '{tabbed.rstrip()}'")  # right only

# Strip specific characters
dashes = "---hello---"
print(f"strip('-'): '{dashes.strip('-')}'")
  1. messy_input ← Alice Smith , clean ← Alice Smith, tabbed ← data

    1messy_input→    Alice Smith    = "   Alice Smith   "2clean→ Alice Smith = messy_input   Alice Smith   .strip()34print(f"With spaces: '{messy_input   Alice Smith   }'")5print(f"Stripped:    '{cleanAlice Smith}'")6print(f"Length before: {len(messy_input   Alice Smith   )}")7print(f"Length after:  {len(cleanAlice Smith)}")89# Different strip variants10tabbed→ 	  data
     = "\t  data  \n"  #@tabbed="\t\tmore\t\t"11print(f"strip():  '{tabbed	  data
    .strip()}'")12print(f"lstrip(): '{tabbed	  data
    .lstrip()}'")  # left only13print(f"rstrip(): '{tabbed	  data
    .rstrip()}'")  # right only1415# Strip specific characters16dashes→ ---hello--- = "---hello---"17print(f"strip('-'): '{dashes---hello---.strip('-')}'")
    outputWith spaces: '   Alice Smith   '
    Stripped:    'Alice Smith'
    Length before: 17
    Length after:  11
    strip():  'data'
    lstrip(): 'data
    '
    rstrip(): '	  data'
    strip('-'): 'hello'
  1. messy_input ← Alice Smith , clean ← Alice Smith, tabbed ← more

    1messy_input→    Alice Smith    = "   Alice Smith   "2clean→ Alice Smith = messy_input   Alice Smith   .strip()34print(f"With spaces: '{messy_input   Alice Smith   }'")5print(f"Stripped:    '{cleanAlice Smith}'")6print(f"Length before: {len(messy_input   Alice Smith   )}")7print(f"Length after:  {len(cleanAlice Smith)}")89# Different strip variants10tabbed→ 		more		 = "\t\tmore\t\t"11print(f"strip():  '{tabbed		more		.strip()}'")12print(f"lstrip(): '{tabbed		more		.lstrip()}'")  # left only13print(f"rstrip(): '{tabbed		more		.rstrip()}'")  # right only1415# Strip specific characters16dashes→ ---hello--- = "---hello---"17print(f"strip('-'): '{dashes---hello---.strip('-')}'")
    outputWith spaces: '   Alice Smith   '
    Stripped:    'Alice Smith'
    Length before: 17
    Length after:  11
    strip():  'more'
    lstrip(): 'more		'
    rstrip(): '		more'
    strip('-'): 'hello'

Users often accidentally add spaces. Always strip input before processing.

strip Remove whitespace: `" hi ".strip()` → `"hi"`

Find substring (search in text)

Check if a string contains another string, and where.

text
find.py
Replay: real traced execution (multi-file project)
text = "Hello World, Hello Python"

# Simple check with 'in'
print(f"'Hello' in text? {'Hello' in text}")
print(f"'Java' in text? {'Java' in text}")

# Find position
pos = text.find("Hello")
print(f"'Hello' first found at: {pos}")

# Find from a position
second_pos = text.find("Hello", pos + 1)
print(f"'Hello' second found at: {second_pos}")

# find() returns -1 if not found (doesn't raise error)
not_found = text.find("Java")
print(f"'Java' found at: {not_found}")

# index() raises error if not found - use when you expect it to exist
# pos = text.index("Java")  # Would raise ValueError
text = "The quick brown fox"

# Simple check with 'in'
print(f"'Hello' in text? {'Hello' in text}")
print(f"'Java' in text? {'Java' in text}")

# Find position
pos = text.find("Hello")
print(f"'Hello' first found at: {pos}")

# Find from a position
second_pos = text.find("Hello", pos + 1)
print(f"'Hello' second found at: {second_pos}")

# find() returns -1 if not found (doesn't raise error)
not_found = text.find("Java")
print(f"'Java' found at: {not_found}")

# index() raises error if not found - use when you expect it to exist
# pos = text.index("Java")  # Would raise ValueError
  1. text ← Hello World, Hello Python, pos ← 0, second_pos ← 13, not_found ← -1

    1text→ Hello World, Hello Python = "Hello World, Hello Python"  #@text="The quick brown fox"23# Simple check with 'in'4print(f"'Hello' in text? {'Hello' in textHello World, Hello Python}")5print(f"'Java' in text? {'Java' in textHello World, Hello Python}")67# Find position8pos→ 0 = textHello World, Hello Python.find("Hello")9print(f"'Hello' first found at: {pos0}")1011# Find from a position12second_pos→ 13 = textHello World, Hello Python.find("Hello", pos0 + 1)13print(f"'Hello' second found at: {second_pos13}")1415# find() returns -1 if not found (doesn't raise error)16not_found→ -1 = textHello World, Hello Python.find("Java")17print(f"'Java' found at: {not_found-1}")
    output'Hello' in text? True
    'Java' in text? False
    'Hello' first found at: 0
    'Hello' second found at: 13
    'Java' found at: -1
  1. text ← The quick brown fox, pos ← -1, second_pos ← -1, not_found ← -1

    1text→ The quick brown fox = "The quick brown fox"23# Simple check with 'in'4print(f"'Hello' in text? {'Hello' in textThe quick brown fox}")5print(f"'Java' in text? {'Java' in textThe quick brown fox}")67# Find position8pos→ -1 = textThe quick brown fox.find("Hello")9print(f"'Hello' first found at: {pos-1}")1011# Find from a position12second_pos→ -1 = textThe quick brown fox.find("Hello", pos-1 + 1)13print(f"'Hello' second found at: {second_pos-1}")1415# find() returns -1 if not found (doesn't raise error)16not_found→ -1 = textThe quick brown fox.find("Java")17print(f"'Java' found at: {not_found-1}")
    output'Hello' in text? False
    'Java' in text? False
    'Hello' first found at: -1
    'Hello' second found at: -1
    'Java' found at: -1

Use in for simple checks, find() when you need the position.

find Find position: `"Hello".find("l")` → `2`, returns `-1` if not found

Replace text

Substitute parts of a string with something else.

message
replace.py
Replay: real traced execution (multi-file project)
original = "Hello World"

# Replace all occurrences
replaced = original.replace("l", "L")
print(f"Replace l→L: {replaced}")

# Replace substring
new_world = original.replace("World", "Python")
print(f"Replace World→Python: {new_world}")

# Original unchanged (strings are immutable)
print(f"Original still: {original}")

# Limit replacements
text = "a-b-c-d-e"
partial = text.replace("-", "_", 2)  # only first 2
print(f"Replace first 2: {partial}")

# Practical: censor words
message = "This is bad and very bad"
censored = message.replace("bad", "***")
print(f"Censored: {censored}")
original = "Hello World"

# Replace all occurrences
replaced = original.replace("l", "L")
print(f"Replace l→L: {replaced}")

# Replace substring
new_world = original.replace("World", "Python")
print(f"Replace World→Python: {new_world}")

# Original unchanged (strings are immutable)
print(f"Original still: {original}")

# Limit replacements
text = "a-b-c-d-e"
partial = text.replace("-", "_", 2)  # only first 2
print(f"Replace first 2: {partial}")

# Practical: censor words
message = "That was ugly behavior"
censored = message.replace("bad", "***")
print(f"Censored: {censored}")
  1. original ← Hello World, replaced ← HeLLo WorLd, new_world ← Hello Python

    1original→ Hello World = "Hello World"23# Replace all occurrences4replaced→ HeLLo WorLd = originalHello World.replace("l", "L")5print(f"Replace l→L: {replacedHeLLo WorLd}")67# Replace substring8new_world→ Hello Python = originalHello World.replace("World", "Python")9print(f"Replace World→Python: {new_worldHello Python}")1011# Original unchanged (strings are immutable)12print(f"Original still: {originalHello World}")1314# Limit replacements15text→ a-b-c-d-e = "a-b-c-d-e"16partial→ a_b_c-d-e = texta-b-c-d-e.replace("-", "_", 2)  # only first 217print(f"Replace first 2: {partiala_b_c-d-e}")1819# Practical: censor words20message→ This is bad and very bad = "This is bad and very bad"  #@message="That was ugly behavior"21censored→ This is *** and very *** = messageThis is bad and very bad.replace("bad", "***")22print(f"Censored: {censoredThis is *** and very ***}")
    outputReplace l→L: HeLLo WorLd
    Replace World→Python: Hello Python
    Original still: Hello World
    Replace first 2: a_b_c-d-e
    Censored: This is *** and very ***
  1. original ← Hello World, replaced ← HeLLo WorLd, new_world ← Hello Python

    1original→ Hello World = "Hello World"23# Replace all occurrences4replaced→ HeLLo WorLd = originalHello World.replace("l", "L")5print(f"Replace l→L: {replacedHeLLo WorLd}")67# Replace substring8new_world→ Hello Python = originalHello World.replace("World", "Python")9print(f"Replace World→Python: {new_worldHello Python}")1011# Original unchanged (strings are immutable)12print(f"Original still: {originalHello World}")1314# Limit replacements15text→ a-b-c-d-e = "a-b-c-d-e"16partial→ a_b_c-d-e = texta-b-c-d-e.replace("-", "_", 2)  # only first 217print(f"Replace first 2: {partiala_b_c-d-e}")1819# Practical: censor words20message→ That was ugly behavior = "That was ugly behavior"21censored→ That was ugly behavior = messageThat was ugly behavior.replace("bad", "***")22print(f"Censored: {censoredThat was ugly behavior}")
    outputReplace l→L: HeLLo WorLd
    Replace World→Python: Hello Python
    Original still: Hello World
    Replace first 2: a_b_c-d-e
    Censored: That was ugly behavior

replace creates a new string - the original is unchanged (strings are immutable).

replace Substitute text: `"Hello".replace("l", "L")` → `"HeLLo"`

Split string (parse CSV)

Break a string into parts using a delimiter.

csv_line
split.py
Replay: real traced execution (multi-file project)
# Split CSV line
csv_line = "Alice,25,Engineer"
parts = csv_line.split(",")

print(f"CSV: {csv_line}")
print(f"Name: {parts[0]}")
print(f"Age: {parts[1]}")
print(f"Job: {parts[2]}")

# Split by whitespace (default)
sentence = "Hello   World   Python"
words = sentence.split()
print(f"Words: {len(words)}")
for word in words:
    print(f"  - {word}")

# Limit splits
data = "a:b:c:d:e"
first_two = data.split(":", 2)  # split at most 2 times
print(f"Limited split: {first_two}")

# Split CSV line
csv_line = "Bob,30,Designer"
parts = csv_line.split(",")

print(f"CSV: {csv_line}")
print(f"Name: {parts[0]}")
print(f"Age: {parts[1]}")
print(f"Job: {parts[2]}")

# Split by whitespace (default)
sentence = "Hello   World   Python"
words = sentence.split()
print(f"Words: {len(words)}")
for word in words:
    print(f"  - {word}")

# Limit splits
data = "a:b:c:d:e"
first_two = data.split(":", 2)  # split at most 2 times
print(f"Limited split: {first_two}")

  1. csv_line ← Alice,25,Engineer, parts ← ['Alice', '25', 'Engineer']

    1# Split CSV line2csv_line→ Alice,25,Engineer = "Alice,25,Engineer"  #@csv_line="Bob,30,Designer"3parts→ ['Alice', '25', 'Engineer'] = csv_lineAlice,25,Engineer.split(",")45print(f"CSV: {csv_lineAlice,25,Engineer}")6print(f"Name: {parts[0]Alice}")7print(f"Age: {parts[1]25}")8print(f"Job: {parts[2]Engineer}")910# Split by whitespace (default)11sentence→ Hello   World   Python = "Hello   World   Python"12words→ ['Hello', 'World', 'Python'] = sentenceHello   World   Python.split()  #?default_split13print(f"Words: {len(words['Hello', 'World', 'Python'])}")14for word in words:
    outputCSV: Alice,25,Engineer
    Name: Alice
    Age: 25
    Job: Engineer
    Words: 3
  2. for word in words:

    pass 1 of 3
    13print(f"Words: {len(words)}")14for wordHello in words['Hello', 'World', 'Python']:15    print(f"  - {wordHello}")
    output  - Hello
    All 3 passes — pass 1 is the card above
    password
    1Hello
    2World
    3Python
  3. data ← a:b:c:d:e, first_two ← ['a', 'b', 'c:d:e']

    17# Limit splits18data→ a:b:c:d:e = "a:b:c:d:e"19first_two→ ['a', 'b', 'c:d:e'] = dataa:b:c:d:e.split(":", 2)  # split at most 2 times20print(f"Limited split: {first_two['a', 'b', 'c:d:e']}")
    outputLimited split: ['a', 'b', 'c:d:e']
  1. csv_line ← Bob,30,Designer, parts ← ['Bob', '30', 'Designer']

    1# Split CSV line2csv_line→ Bob,30,Designer = "Bob,30,Designer"3parts→ ['Bob', '30', 'Designer'] = csv_lineBob,30,Designer.split(",")45print(f"CSV: {csv_lineBob,30,Designer}")6print(f"Name: {parts[0]Bob}")7print(f"Age: {parts[1]30}")8print(f"Job: {parts[2]Designer}")910# Split by whitespace (default)11sentence→ Hello   World   Python = "Hello   World   Python"12words→ ['Hello', 'World', 'Python'] = sentenceHello   World   Python.split()13print(f"Words: {len(words['Hello', 'World', 'Python'])}")14for word in words:
    outputCSV: Bob,30,Designer
    Name: Bob
    Age: 30
    Job: Designer
    Words: 3
  2. for word in words:

    pass 1 of 3
    13print(f"Words: {len(words)}")14for wordHello in words['Hello', 'World', 'Python']:15    print(f"  - {wordHello}")
    output  - Hello
    All 3 passes — pass 1 is the card above
    password
    1Hello
    2World
    3Python
  3. data ← a:b:c:d:e, first_two ← ['a', 'b', 'c:d:e']

    17# Limit splits18data→ a:b:c:d:e = "a:b:c:d:e"19first_two→ ['a', 'b', 'c:d:e'] = dataa:b:c:d:e.split(":", 2)  # split at most 2 times20print(f"Limited split: {first_two['a', 'b', 'c:d:e']}")
    outputLimited split: ['a', 'b', 'c:d:e']

Splitting is essential for parsing structured data like CSV files.

split Break apart: `"a,b,c".split(",")` → `["a", "b", "c"]`

Exercise: more_ops.py

Explore more operations: slicing, startswith, endswith, join