Python online course

Searching and Inspecting Strings in Python

Learn how to count, find, test, and replace text in Python strings with clear examples of count(), endswith(), find(), replace(), and in.

A Python string is an ordered sequence of text characters. Strings can contain words, spaces, punctuation, and other characters. A smaller sequence searched for inside a string is called a substring.

For example:

message = 'Hello world!'
print(message)

String operations are usually performed with dot notation. A string method is a function called on a string object:

message.count('world')
message.endswith('!')
message.find('llo')
message.replace('Hello', 'Bye')

Python strings are immutable. This means their existing characters cannot be changed in place. Most string methods return a result, so assign that result when you want to keep it.

message = 'Hello world!'
updated_message = message.replace('Hello', 'Bye')

print(message)          # Hello world!
print(updated_message)  # Bye world!

Calling message.replace('Hello', 'Bye') does not modify message by itself.

Core string search and replacement methods

MethodPurposeReturn typeNo-match behaviorExample use
count()Count non-overlapping substring occurrencesIntegerReturns 0text.count('cat')
endswith()Test a suffixBooleanReturns Falsefilename.endswith('.pdf')
find()Find the first substring positionIntegerReturns -1text.find('cat')
replace()Create text with substitutionsStringReturns the original text if nothing matchestext.replace('old', 'new')

Counting text with count()

Use str.count(substring) when the quantity of matches matters. It returns an integer: the number of non-overlapping occurrences of the substring.

message = 'Hello world!'
message.count('world')  # 1
message.count('Python') # 0

A result of 0 means that the exact substring was not found. The search is case-sensitive, so uppercase and lowercase letters differ:

text = 'Python python'
print(text.count('python'))  # 1
print(text.count('Python'))  # 1
print(text.count('PYTHON'))  # 0

count() can also receive optional start and end positions. The start position is included, while the end position is excluded.

text = 'one two one two'
print(text.count('one', 0, 7))  # 1

Because matches cannot overlap, a substring that starts inside a previous match is not counted as a separate match by count().

Checking endings with endswith()

Use str.endswith(suffix) when you need to know whether text finishes with particular characters. It returns a Boolean value: True or False.

message = 'Hello world!'
print(message.endswith('!'))  # True
print(message.endswith('?'))  # False

Common uses include checking filename extensions and validating punctuation:

filename = 'photo.png'
print(filename.endswith('.png'))  # True

sentence = 'Is this correct?'
print(sentence.endswith('?'))      # True

You can provide a tuple of allowed suffixes when several endings are valid:

filename = 'photo.png'
allowed = ('.png', '.jpg', '.jpeg')
print(filename.endswith(allowed))  # True

The comparison is case-sensitive. Normalize the filename first when capitalization should not matter. lower() creates a lowercase string for the comparison:

filename = 'REPORT.PDF'
print(filename.lower().endswith('.pdf'))  # True

For input that may contain extra whitespace, clean it before testing:

filename = ' REPORT.PDF '
print(filename.strip().lower().endswith('.pdf'))  # True

Finding a position with find()

Use str.find(substring) to locate the first occurrence of a substring. A successful search returns the substring's starting index. An index is a zero-based numeric position, so the first character is at position 0.

message = 'Hello world!'
position = message.find('llo')
print(position)  # 2

The search for 'llo' starts at index 2: H is at index 0, e at index 1, and l at index 2.

If the substring is absent, find() returns -1 rather than raising an exception.

message = 'Hello world!'
print(message.find('Python'))  # -1

You can use the result for a presence check, but compare explicitly with -1:

position = message.find('world')
if position != -1:
    print('Found at index', position)
if 'world' in message:
    print('The word is present')

find() also accepts optional start and end positions:

text = 'one two one'
print(text.find('one', 4))  # 8

Like count(), find() is case-sensitive:

text = 'Python python'
print(text.find('python'))  # 7
print(text.find('PYTHON'))  # -1

Replacing text with replace()

Use str.replace(old, new) to create a string in which matching text is substituted. By default, every non-overlapping match is replaced.

message = 'Hello world!'
updated_message = message.replace('Hello', 'Bye')

print(updated_message)  # Bye world!
print(message)          # Hello world!

The method returns a new string and leaves the source string unchanged. Assign the result back to the same variable when that is the intended behavior:

text = 'red red red'
text = text.replace('red', 'blue')
print(text)  # blue blue blue

The optional third argument, count, limits how many replacements occur, starting from the left:

text = 'red red red'
print(text.replace('red', 'blue', 2))  # blue blue red

Replacement is case-sensitive:

text = 'Cat cat'
print(text.replace('cat', 'dog'))  # Cat dog

If you need case-insensitive replacement, prepare the text or use a pattern-based approach suited to the requirement. Simply calling replace() does not ignore capitalization.

Choosing an appropriate operation

GoalRecommended operationReason
Determine whether text appears anywheresubstring in textIt states the existence test directly and returns a Boolean.
Get the location of texttext.find(substring)It returns the first zero-based starting index or -1.
Count matchestext.count(substring)It returns the number of non-overlapping occurrences.
Validate a suffixtext.endswith(suffix)It directly tests the ending and returns True or False.
Create modified texttext.replace(old, new)It returns a new string containing the substitutions.

Use find() when the position is useful, such as when you need to inspect the text around a match. Use in when the position is unnecessary and readability is the priority.

Interactive demonstration

These statements can be entered in an interactive Python shell:

message = 'Hello world!'
print(message.count('world'))
print(message.endswith('!'))
print(message.find('llo'))
print(message.replace('Hello', 'Bye'))

The output is:

1
True
2
Bye world!

Troubleshooting string searches

find() returns -1 unexpectedly

The searched value may differ in capitalization, spacing, or punctuation. Inspect the exact input and normalize case when appropriate:

text = 'Welcome, Python!'
print(text.lower().find('python'))  # 9

For broader case-insensitive comparisons, casefold() can be more suitable than lower() for some languages.

A find() condition fails at the beginning of the string

If a match begins at index 0, testing the raw result as a condition treats that valid index as false. Use text.find(value) != -1, or use value in text when you do not need the position.

replace() does not seem to change the variable

The return value may have been ignored. Strings cannot be edited in place, so assign the returned string:

text = text.replace(old, new)

count() returns fewer matches than expected

Check for case differences and remember that count() counts non-overlapping matches. If overlapping matches are required, a more specialized searching technique is needed.

endswith() returns False for a seemingly correct extension

The filename may contain uppercase letters or trailing whitespace. Clean and normalize it before testing:

filename = ' REPORT.PDF '
valid = filename.strip().lower().endswith('.pdf')
print(valid)  # True

Summary

  • A string is an ordered sequence of text characters, and a substring is a smaller sequence searched for within it.
  • Call string methods with dot notation, such as text.find('word').
  • count() returns the number of non-overlapping matches.
  • endswith() returns a Boolean suffix test and can accept a tuple of suffixes.
  • find() returns a zero-based index or -1 when no match exists.
  • in is a readable choice when only substring existence matters.
  • replace() returns new text; it replaces all matches by default and accepts an optional replacement limit.
  • These operations are case-sensitive unless you normalize the text first.
  • String methods do not change the original string in place because strings are immutable.

For foundational string concepts, see What Are Strings and Python strings. Related operations are introduced in String Functions and Accessing Individual Characters.