Skip to main content

How to Find the Index of a Substring in Python

Finding the position (index) of a substring within a string is a fundamental operation in Python. Whether you're parsing text, validating input, extracting data, or searching log files, knowing exactly where a substring appears is essential.

Python provides several built-in methods and tools for this task, each suited for different scenarios. This guide covers all the key approaches with practical examples.

The find() method is the most commonly used approach. It returns the index of the first occurrence of the substring. If the substring is not found, it returns -1 instead of raising an error.

text = "hello world"

index = text.find("world")
print(index)

Output:

6

The substring "world" starts at index 6 in the string "hello world".

Handling Substrings Not Found

text = "hello world"

index = text.find("python")
print(index)

Output:

-1

Returning -1 makes find() safe to use in conditional checks:

text = "hello world"

if text.find("world") != -1:
print("Substring found!")
else:
print("Substring not found.")

Output:

Substring found!

Using index()

The index() method works exactly like find(), but instead of returning -1 when the substring isn't found, it raises a ValueError.

text = "hello world"

index = text.index("hello")
print(index)

Output:

0
index() raises an error if the substring is missing
text = "hello world"

index = text.index("python")
# ValueError: substring not found

Always use find() when the substring might not exist, or wrap index() in a try/except block:

text = "hello world"

try:
index = text.index("python")
print(index)
except ValueError:
print("Substring not found.")

Output:

Substring not found.

Searching from a Specific Position

Both find() and index() accept optional start and end parameters to limit the search to a specific portion of the string.

Syntax:

str.find(substring, start, end)

Start Searching After a Specific Index

text = "hello world, hello python"

# Find "hello" starting from index 5
index = text.find("hello", 5)
print(index)

Output:

13

The first "hello" at index 0 is skipped because the search starts at index 5. The second "hello" at index 13 is returned.

Searching Within a Range

text = "apple banana apple cherry apple"

# Search for "apple" only between indices 5 and 25
index = text.find("apple", 5, 25)
print(index)

Output:

13

Finding All Occurrences of a Substring

find() only returns the first match. To find all occurrences, use a loop:

text = "the cat sat on the mat with the bat"
substring = "the"

positions = []
start = 0

while True:
index = text.find(substring, start)
if index == -1:
break
positions.append(index)
start = index + 1 # Move past the current match

print(f"'{substring}' found at indices: {positions}")

Output:

'the' found at indices: [0, 15, 29]
tip

If you want non-overlapping matches, use start = index + len(substring) instead of start = index + 1.

Using rfind() to Find the Last Occurrence

The rfind() method searches from the end of the string and returns the index of the last occurrence:

text = "hello world, hello python, hello AI"

# Last occurrence of "hello"
last_index = text.rfind("hello")
print(f"Last 'hello' at index: {last_index}")

# First occurrence of "hello"
first_index = text.find("hello")
print(f"First 'hello' at index: {first_index}")

Output:

Last 'hello' at index: 27
First 'hello' at index: 0

There's also an rindex() method that works like rfind() but raises a ValueError if the substring isn't found.

Using Regular Expressions with re.search()

For advanced pattern matching - such as case-insensitive searches, wildcard patterns, or complex substring patterns - use the re module:

import re

text = "Hello, Tutorial Reference for you!"

# Case-sensitive search
match = re.search(r"Tutorial", text)
if match:
print(f"Found at index: {match.start()}")

Output:

Found at index: 7
import re

text = "Hello, Tutorial Reference for you!"

# Find first occurrence of "tutorial" regardless of case
match = re.search(r"tutorial", text, re.IGNORECASE)
if match:
print(f"Found '{match.group()}' at index: {match.start()}")

Output:

Found 'Tutorial' at index: 7

Finding All Matches with Indices

import re

text = "Hello, TUTORIAL REFERENCE, Tutorial Reference, tutorial reference!"

matches = [(m.start(), m.group()) for m in re.finditer(r"tutorial", text, re.IGNORECASE)]
for index, value in matches:
print(f" '{value}' at index {index}")

Output:

  'TUTORIAL' at index 7
'Tutorial' at index 27
'tutorial' at index 47

Using the in Operator (Existence Check Only)

If you only need to know whether a substring exists (not its position), the in operator is the simplest and most readable option:

text = "hello world"

if "world" in text:
print("Found!")
else:
print("Not found.")

Output:

Found!
note

The in operator returns a boolean (True or False), not an index. Use find() or index() when you need the actual position.

Quick Comparison

MethodReturnsNot Found BehaviorBest For
find()Index (int)Returns -1Most use cases (recommended)
index()Index (int)Raises ValueErrorWhen absence is an error
rfind()Index (int)Returns -1Finding the last occurrence
re.search()Match objectReturns NonePattern matching, case-insensitive
in operatorBooleanReturns FalseSimple existence check

Conclusion

  • For most substring index lookups, find() is the safest and most Pythonic choice. It handles missing substrings gracefully by returning -1. Use index() when you expect the substring to always be present and want an error if it's not.
  • For finding the last occurrence, use rfind().
  • When you need advanced pattern matching or case-insensitive searches, reach for re.search().

Choose the method that matches your specific needs and error-handling preferences.