Skip to content

How to Search Strings Using find() and index() Methods in Python

Learn how to use Python's .find() (returns -1 on failure) and .index() (raises ValueError) methods for substring searches, with practical examples for error handling and data parsing.

Locating substrings within text is fundamental to parsing data, validating input, and processing logs. Python provides two primary methods for finding substring positions: .find() and .index(). While both return the starting index when the substring exists, they behave very differently when it doesn't: a distinction that significantly impacts how you structure your error handling and program flow. This guide clarifies when to use each method for more robust string processing.

The Safe Approach: find()

The .find() method returns the index of the first occurrence of a substring, or -1 if not found. This makes it ideal for conditional checks where the substring may or may not exist:

log_entry = "2026-05-15 INFO: Connection established"

error_pos = log_entry.find("ERROR")

if error_pos == -1:
    print("No errors detected in log entry")
else:
    print(f"Error found at position {error_pos}")

info_pos = log_entry.find("INFO")
print(f"INFO tag found at index: {info_pos}")  

Output:

No errors detected in log entry
INFO tag found at index: 11

You can also specify start and end positions to search within a specific range:

text = "banana"

result = text.find("a", 2)
print(result)  # Output: 3

result = text.find("a", 2, 4)
print(result)  # Output: 3

The Strict Approach: index()

The .index() method also returns the substring's position, but raises a ValueError when the substring isn't found. Use this when the substring's presence is required for your program logic:

config_line = "database_host: localhost"

try:
    separator_pos = config_line.index(":")
    key = config_line[:separator_pos].strip()
    value = config_line[separator_pos + 1:].strip()
    print(f"Config: {key} = {value}")
except ValueError:
    print("Invalid configuration format: missing separator")

The exception-based approach makes code intent clearer: if execution continues past .index(), you're guaranteed the substring exists:

def parse_email(email):
    """Extract username and domain from email address."""
    try:
        at_position = email.index("@")
        username = email[:at_position]
        domain = email[at_position + 1:]
        return username, domain
    except ValueError:
        raise ValueError(f"Invalid email format: {email}")


user, domain = parse_email("user@example.com")
print(f"User: {user}, Domain: {domain}")

Output:

User: user, Domain: example.com

Method Comparison

Aspect .find() .index()
When found Returns index Returns index
When not found Returns -1 Raises ValueError
Works on Strings only Strings, lists, tuples
Best for Optional searches Required substrings
Error handling Conditional check Try/except block

Choosing the Right Method

def highlight_keyword(text, keyword):
    """Highlight keyword if present, otherwise return original."""
    pos = text.find(keyword)
    if pos != -1:
        return f"{text[:pos]}**{keyword}**{text[pos + len(keyword):]}"
    return text


def extract_value(data, prefix):
    """Extract value after prefix: prefix must be present."""
    start = data.index(prefix) + len(prefix)
    return data[start:].split()[0]

Finding All Occurrences

Both methods find only the first occurrence. To find all positions:

def find_all(text, substring):
    """Find all occurrences of substring in text."""
    positions = []
    start = 0
    
    while True:
        pos = text.find(substring, start)
        if pos == -1:
            break
        positions.append(pos)
        start = pos + 1
    
    return positions


text = "banana"
print(find_all(text, "a"))  # Output: [1, 3, 5]

The in Operator Alternative

When you only need to check existence without needing the position, use the in operator for clearer, more Pythonic code:

log_message = "ERROR: Database connection failed"

if "ERROR" in log_message:
    print("Error detected!")

status = "critical" if "ERROR" in log_message else "normal"

By understanding the behavioral difference between silent failure (-1) and explicit exceptions (ValueError), you can write string processing code that clearly communicates its intent and handles edge cases appropriately.

Navigation