Learn Without Walls
← Lesson 2 Lesson 3 of 4 Lesson 4 →

Lesson 7.3: Searching and Replacing

By the end of this lesson, you will be able to:

The in Operator

The simplest way to check if a substring exists within a string is the in operator.

sentence = "Python is a powerful programming language"

print("Python" in sentence)
print("java" in sentence)
print("powerful" in sentence)

# Using 'not in'
print("java" not in sentence)
True False True True
Remember: The in operator is case-sensitive. "python" in "Python is great" returns False. Convert both to lowercase for case-insensitive checks.
text = "Python is Great"
search = "python"

# Case-insensitive search
if search.lower() in text.lower():
    print("Found it!")
Found it!

The find() Method

find() returns the index of the first occurrence of a substring. If not found, it returns -1 (instead of raising an error).

text = "Hello, World! Hello, Python!"

print(text.find("Hello"))     # First occurrence
print(text.find("World"))     # Position of "World"
print(text.find("Java"))      # Not found
0 7 -1

Searching from a Starting Position

You can specify where to start searching.

text = "Hello, World! Hello, Python!"

# Find second "Hello" by starting after the first
first = text.find("Hello")
second = text.find("Hello", first + 1)
print(f"First 'Hello' at index: {first}")
print(f"Second 'Hello' at index: {second}")
First 'Hello' at index: 0 Second 'Hello' at index: 14

Using find() Safely

email = "user@example.com"
at_pos = email.find("@")

if at_pos != -1:
    username = email[:at_pos]
    domain = email[at_pos + 1:]
    print(f"Username: {username}")
    print(f"Domain: {domain}")
else:
    print("Invalid email")
Username: user Domain: example.com

find() vs index()

Key Difference: find() returns -1 when not found. index() raises a ValueError when not found. Use find() when missing values are expected; use index() when missing values are errors.
text = "Python programming"

# find() returns -1
print(text.find("Java"))

# index() raises ValueError
# text.index("Java")  # ValueError: substring not found

# Both work the same when substring IS found
print(text.find("prog"))
print(text.index("prog"))
-1 7 7

Searching from the Right: rfind() and rindex()

rfind() and rindex() search from the right (end) of the string and return the index of the last occurrence.

path = "/home/user/documents/report.pdf"

# Find last "/" to get the filename
last_slash = path.rfind("/")
filename = path[last_slash + 1:]
print(f"Filename: {filename}")

# Find last "." to get the extension
last_dot = path.rfind(".")
extension = path[last_dot + 1:]
print(f"Extension: {extension}")
Filename: report.pdf Extension: pdf

Finding All Occurrences

text = "the cat sat on the mat near the hat"
search = "the"

positions = []
start = 0
while True:
    pos = text.find(search, start)
    if pos == -1:
        break
    positions.append(pos)
    start = pos + 1

print(f"'{search}' found at positions: {positions}")
'the' found at positions: [0, 15, 28]

Advanced replace()

Building on what you learned in Lesson 1, here are more advanced uses of replace().

# Censoring words
message = "The password is secret123"
censored = message.replace("secret123", "*****")
print(censored)

# Normalizing whitespace
messy = "too   many     spaces"
while "  " in messy:
    messy = messy.replace("  ", " ")
print(messy)

# Converting separators
csv_data = "name,age,city"
tab_data = csv_data.replace(",", "\t")
print(tab_data)
The password is ***** too many spaces name age city

Try It Yourself

Given url = "https://www.example.com/path/to/page", use find() and slicing to extract just the domain name ("www.example.com").

Introduction to Pattern Matching

While find() and replace() work great for exact matches, sometimes you need to search for patterns rather than exact text. Python has a module called re (regular expressions) for this, which you will explore in later modules.

Preview: Regular expressions let you search for patterns like "any digit", "any word that starts with a capital letter", or "any email address format". For now, the string methods you have learned cover most common needs.

For now, here are some common pattern-checking techniques using the methods you already know:

# Check if a string contains only digits
pin = "1234"
print(f"Is PIN all digits? {pin.isdigit()}")

# Check if input looks like an email
email = "user@example.com"
has_at = "@" in email
has_dot = "." in email
print(f"Looks like email? {has_at and has_dot}")
Is PIN all digits? True Looks like email? True

Check Your Understanding

  1. What does "hello world".find("world") return?
  2. What does "hello world".find("python") return?
  3. What is the difference between find() and index()?
  4. How does rfind() differ from find()?
  1. 6 (the index where "world" begins)
  2. -1 (not found)
  3. find() returns -1 when not found; index() raises a ValueError
  4. rfind() searches from the right and returns the last occurrence

Key Takeaways