The easiest way to check whether a string contains a substring in Python is the in operator. It returns True if the substring exists and False otherwise.
Python does not have a common str.contains() method. Use substring in text instead.
Tested on: Python 3.13.3; kernel 6.14.0-37-generic.
Quick answer: check if a string contains a substring
Use substring in text.
text = "Python Tutorial"
if "Python" in text:
print("Found Python")
if "Java" in text:
print("Found Java")The first check prints because "Python" appears in the string. The second check does nothing because "Java" is not present.
Python string contains substring quick reference
| Task | Use |
|---|---|
| Check if substring exists | substring in text |
| Check if substring does not exist | substring not in text |
| Case-insensitive contains | substring.casefold() in text.casefold() |
| Find first position | text.find(substring) |
| Find first position or raise error | text.index(substring) |
| Count occurrences | text.count(substring) |
| Check multiple substrings, any match | any(s in text for s in substrings) |
| Check multiple substrings, all match | all(s in text for s in substrings) |
| Whole-word match | re.search(r"\bword\b", text) |
| Pattern match | re.search(pattern, text) |
| Starts with substring | text.startswith(prefix) |
| Ends with substring | text.endswith(suffix) |
Check if string contains substring using in
The in operator is the recommended method for normal checks. It returns True or False, is readable, and is case-sensitive.
text = "Python Tutorial"
print("Python" in text)
print("Tutorial" in text)
print("Java" in text)Use in when you only need to know whether the substring exists. For prefix checks at the start of a string, see Python startswith().
Check if string does not contain substring
Use not in for negative checks. It is clearer than testing find() against -1.
line = "INFO: service started"
if "ERROR" not in line:
print("No error in this line")
if "WARN" not in line:
print("No warning in this line")Useful for filtering log lines, skipping values, and validating input.
Python has no str.contains() method
Some languages expose contains(), indexOf(), or includes(). Python’s normal syntax is substring in string.
text = "hello world"
# Correct
print("world" in text)
# Wrong — strings have no contains() method
try:
text.contains("world")
except AttributeError as exc:
print(type(exc).__name__)Do not write text.contains(substring) in Python.
Case-sensitive substring check
The in operator is case-sensitive.
text = "Python Tutorial"
print("Python" in text)
print("python" in text)Use exact casing when case matters, such as product codes, file extensions, or protocol names.
Case-insensitive substring check
Use lower() for simple ASCII-style checks. Use casefold() for more robust case-insensitive matching. Normalize both the text and the substring.
text = "Python Tutorial"
needle = "python"
print(needle.lower() in text.lower())
print(needle.casefold() in text.casefold())Do not convert only one side when the substring may come from user input or a variable.
find() vs in
| Method | Return value | Best for |
|---|---|---|
substring in text |
True or False |
Simple contains check |
text.find(substring) |
Index or -1 |
Need position without exception |
text = "Python Tutorial"
print("Tutorial" in text)
print(text.find("Tutorial"))
print(text.find("Java"))Use in when you only need existence. Use find() when you need the starting index. Do not choose find() just to get True/False unless you also need the position.
A common mistake is writing if text.find("x"): — that fails when the match is at index 0 because 0 is falsy.
index() vs find()
| Method | If found | If not found | Best for |
|---|---|---|---|
find() |
Returns index | Returns -1 |
Safe lookup |
index() |
Returns index | Raises ValueError |
Missing substring should be an error |
text = "Python Tutorial"
print(text.index("Python"))
try:
text.index("Java")
except ValueError as exc:
print(type(exc).__name__)Use index() when a missing substring should stop normal flow. Use find() when missing text is an expected outcome.
Count how many times a substring appears
text.count(substring) returns the number of non-overlapping occurrences. It is case-sensitive.
text = "banana"
print(text.count("a"))
print(text.count("na"))
print(text.count("z"))
text2 = "Banana BANANA"
print(text2.lower().count("ana"))count() > 0 can test existence, but use in when you only need a yes-or-no answer. Use count() when the number of matches matters.
Check multiple substrings
Use any() when at least one substring should match. Use all() when every substring must match.
text = "Python data tutorial"
keywords = ["Python", "Java"]
required = ["Python", "tutorial"]
print(any(word in text for word in keywords))
print(all(word in text for word in required))This pattern works well for keyword filters and simple validation rules. See Python any() and all() for more on these helpers.
Whole-word substring match
The in operator checks characters, not word boundaries.
text = "concatenate"
print("cat" in text)
import re
print(bool(re.search(r"\bcat\b", text)))
print(bool(re.search(r"\bcat\b", "a cat sat")))"cat" appears inside "concatenate", but the whole-word regex matches only standalone "cat". For building strings from matched pieces, see Python concatenate strings.
Substring pattern match using regex
Use re.search() when you need a pattern, not a fixed substring. Good for digits, email-like patterns, whole words, flexible spacing, and prefix or suffix rules.
import re
text = "Contact: user@example.com"
print(bool(re.search(r"\d+", text)))
print(bool(re.search(r"[\w.-]+@[\w.-]+\.\w+", text)))Do not use regex for simple fixed substring checks. Use in first, and reach for Python regex only when the match rule is more flexible.
Find all substring positions
Use find() in a loop when you need every starting position. Built-in search finds non-overlapping positions when you advance the start index correctly.
text = "banana"
needle = "ana"
start = 0
positions = []
while True:
pos = text.find(needle, start)
if pos == -1:
break
positions.append(pos)
start = pos + 1
print(positions)For overlapping matches, use custom logic or regex. Built-in count() counts non-overlapping occurrences only.
Check overlapping substring matches
text = "aaaa"
needle = "aa"
print(text.count(needle))
import re
print(len(re.findall(f"(?=({needle}))", text)))count() returns 2 for non-overlapping "aa" in "aaaa". The regex lookahead finds overlapping starts when that behavior matters.
Substring vs subsequence
A substring is contiguous. A subsequence is not necessarily contiguous.
word = "Hello"
print("ell" in word)
print("Hlo" in word)
def is_subsequence(text, pattern):
it = iter(text)
return all(ch in it for ch in pattern)
print(is_subsequence(word, "Hlo"))"ell" is a substring of "Hello". "Hlo" is a subsequence but not a substring. Most everyday “contains” checks mean substring, not subsequence.
Practical examples
log = "ERROR: database timeout"
user_input = "I love Python"
email = "user@example.com"
urls = ["https://example.com", "http://test.local/page"]
files = ["report.txt", "notes.md", "photo.jpg"]
print("ERROR" in log)
print("Python" in user_input.lower())
print("@" in email)
print([url for url in urls if "example.com" in url])
print([name for name in files if "report" in name])These patterns fit logs, user input, email checks, URL filtering, and filename searches.
Common mistakes to avoid
- Looking for
text.contains()in Python. - Using
find()incorrectly:if text.find("x"):fails when the match is at index0. - Forgetting that checks are case-sensitive.
- Using
lower()on only one side. - Using
inwhen you need whole-word matching. - Using regex for simple substring checks.
- Forgetting that
count()counts non-overlapping occurrences. - Searching for a non-string value inside a string.
- Treating empty substring as a normal search term.
- Using
index()without handlingValueError. - Using a
find()result of-1as a slice index.
Summary
Use substring in text for normal substring checks. Use not in for negative checks. Use casefold() when case should not matter. Use find() or index() when you need the position. Use count() when you need the number of occurrences. Use regex only for patterns or whole-word matching. For extracting part of a string, see Python substring and slicing.
References
- Python membership operators (
in,not in) - Python
str.find()documentation - Python
str.index()documentation - Python
str.count()documentation - Python
re.search()documentation

