Sitelet https://howtodoinjava.com/python-examples/string-start-with-ends-with/

Python: Check if String Starts or Ends with a Substring

Check if a Python string starts or ends with a substring using startswith(), endswith(), regex with re.escape() and \Z, or slicing, with pitfalls.

Python

We check whether a Python string starts or ends with a substring using the startswith() and endswith() methods, and for patterns we use regular expressions with re.match() or re.search(). Slicing is a third option, though it needs the length of the substring.

import re

text = "HowToDoInJava.com"
start, end = "How", "com"

s1 = text.startswith(start)                      # True
e1 = text.endswith(end)                          # True
s2 = re.match(re.escape(start), text) is not None   # True
e2 = re.search(re.escape(end) + r"\Z", text) is not None   # True
s3 = text[:len(start)] == start                  # True
e3 = text[-len(end):] == end                     # True

In this Python tutorial, we compare the approaches, check both ends at once, ignore case, and look at the pitfalls of each. The detailed method pages are Python startswith() and Python endswith(). The examples run on Python 3.14.

1. Check if String starts or ends with Substring using Regular Expressions

The re.match() function matches only at the start of the string, and re.search() looks anywhere, so an anchor decides the position. With re.search(), the caret ^ anchors at the start, and \Z anchors at the very end; re.match() needs no caret.

starts = bool(re.match(r"How", text))          # True
ends_dollar = bool(re.search(r"com$", "site.com\n"))   # True, $ also matches before a final newline
ends_z = bool(re.search(r"com\Z", "site.com\n"))       # False, \Z means the real end

We wrap fixed text in re.escape() before putting it into a pattern, because characters such as . have a special meaning. Without it, re.search(“.com$”, “xcom”) matches, since the dot stands for any character.

loose = bool(re.search(".com$", "xcom"))                 # True, wrong
exact = bool(re.search(re.escape(".com") + r"\Z", "xcom"))   # False

2. Check if String starts or ends with Substring using Built-in Methods

The startswith() method returns True if the string starts with the given prefix, and endswith() returns True if it ends with the given suffix; otherwise both return False. Both accept a tuple, so one call checks several options.

url = "https://example.com/report.pdf"
secure = url.startswith(("https://", "sftp://"))     # True
document = url.endswith((".pdf", ".docx"))           # True

A list of options raises TypeError, so we wrap it with tuple(). Both methods are case-sensitive, so we lower-case the string first for user input.

3. Check if String starts or ends with Substring using Slicing

Slicing compares the first or last characters with the substring. It works, but the length must match the substring, and an empty end needs care because text[-0:] is the whole string.

prefix_ok = text[:3] == "How"         # True
suffix_ok = text[-3:] == "com"        # True
empty_end = text[-len(""):] == ""     # False, -0 means the whole string

For that reason, slicing is mainly useful when we need the prefix itself, not only a yes-or-no answer.

4. Checking Both Ends at Once

Some formats need both checks, such as a quoted value or a bracketed tag. The two methods combine with and, and re.fullmatch(), which must match the whole string, does it in one pattern.

value = '"Lokesh"'
quoted = value.startswith('"') and value.endswith('"')     # True
inner = value[1:-1] if quoted else value                   # 'Lokesh'
tag = bool(re.fullmatch(r"\[.*\]", "[ERROR]"))             # True

Since Python 3.9, removeprefix() and removesuffix() strip a known prefix or suffix and return the rest, which replaces many slicing tricks.

5. Which Approach to Use

The built-in methods are the clearest choice for fixed text, and regex is for patterns.

ApproachBest forWatch out for
startswith() / endswith()Fixed text, several options with a tupleCase-sensitive; a list raises TypeError
re.match() / re.search() with \ZPatterns such as digits or any extensionEscape fixed text with re.escape(); $ matches before a final newline
SlicingGetting the prefix or suffix itselfThe length must be exact; -0 slices everything
removeprefix() / removesuffix()Stripping a known prefix or suffixReturn the string unchanged when there is no match

6. Starts and Ends With FAQs

Case, empty strings and speed are the details that decide which check to write.

6.1. How do we ignore case?

We normalize both sides, text.lower().startswith(prefix.lower()), or pass re.IGNORECASE to a regex. For non-English text, casefold() is more thorough than lower().

6.2. Does an empty string count as a prefix?

Yes. text.startswith(“”) and text.endswith(“”) always return True, which matters when the prefix comes from user input that can be empty.

6.3. Which approach is fastest?

The built-in methods are the fastest for fixed text, slicing is close, and a regex is slower unless the pattern is compiled once and reused. For most code, readability decides, and that favors the methods.

7. Conclusion

For fixed text, startswith() and endswith() are the clearest checks, and a tuple covers several options. Regular expressions handle patterns when the text is escaped and the end is anchored with \Z, and slicing is best kept for the cases where we need the prefix itself.

8. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.