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.
Using find() (Recommended)
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 missingtext = "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]
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
Case-Insensitive Search
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!
The in operator returns a boolean (True or False), not an index. Use find() or index() when you need the actual position.
Quick Comparison
| Method | Returns | Not Found Behavior | Best For |
|---|---|---|---|
find() | Index (int) | Returns -1 | Most use cases (recommended) |
index() | Index (int) | Raises ValueError | When absence is an error |
rfind() | Index (int) | Returns -1 | Finding the last occurrence |
re.search() | Match object | Returns None | Pattern matching, case-insensitive |
in operator | Boolean | Returns False | Simple existence check |
Conclusion
- For most substring index lookups,
find()is the safest and most Pythonic choice. It handles missing substrings gracefully by returning-1. Useindex()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.