Python startswith() Method: Prefix Checks, Tuples and Ranges

Use Python str.startswith() to check prefixes, filter log lines with a tuple, skip fields with start and end, and compare removeprefix() and slicing.

Python

The Python str.startswith() method returns True when a string begins with the given prefix and False otherwise. Reading log files is a good example, where we keep the lines that start with ERROR and skip the lines that start with #.

line = "ERROR disk is full"
is_error = line.startswith("ERROR")     # True
is_info = line.startswith("INFO")       # False

We filter a small log with a tuple of prefixes, skip a date field with start, ignore case, and compare startswith() with removeprefix() and slicing. The code was checked on Python 3.14.

1. Syntax and Return Value

Like its sibling endswith(), the method takes a prefix and two optional indexes, and it is case-sensitive.

str.startswith(prefix[, start[, end]]) -> bool
  • prefix is a string or a tuple of strings.
  • start is the index where the check begins (default 0).
  • end is the index where the check stops; the character at end is not included.

The return value is a bool. The method returns either True, when the string (or the slice str[start:end]) begins with the prefix or with any prefix in the tuple, or False otherwise.

2. Filtering Log Lines with a Tuple of Prefixes

A tuple lets one call match several prefixes. In a log file, that picks out every warning and error line in a single list comprehension.

log = ["INFO started", "WARN low memory", "ERROR disk is full", "INFO stopped"]
problems = [line for line in log if line.startswith(("WARN", "ERROR"))]
# ['WARN low memory', 'ERROR disk is full']

As with endswith(), a list of prefixes must be wrapped with tuple(prefixes), or the call raises TypeError.

3. Checking from a Position

When a line has a fixed-width field in front, such as a date, start moves the check past it. Because end is exclusive, a range that is too short cuts the prefix and the result becomes False.

line = "2026-10-09 ERROR disk is full"
at_11 = line.startswith("ERROR", 11)        # True
short = line.startswith("ERROR", 11, 14)    # False, the slice is "ERR"

4. Case-Insensitive Checks and Comment Lines

User input and file content rarely have a fixed case or fixed indentation. We normalize the string first with lower() or lstrip(), and call startswith() on the result.

asks_help = "Help me".lower().startswith("help")   # True

config = ["# timeout in seconds", "timeout=30", "", "  # retries", "retries=3"]
settings = 
# ['timeout=30', 'retries=3']

5. startswith() vs removeprefix() vs Slicing

These approaches all look at the beginning of a string, but they return different things. We use startswith() for a yes-or-no answer and removeprefix() (Python 3.9+) when we need the rest of the string.

url = "https://example.com"
secure = url.startswith("https://")       # True
host = url.removeprefix("https://")       # 'example.com'
same = url[:8] == "https://"              # True, but the 8 must match the prefix length
ApproachReturnsWatch out for
s.startswith(p)True or FalseCase-sensitive
s.removeprefix(p)The string without the prefixReturns the string unchanged when the prefix is missing
s[:n] == pTrue or FalseA wrong n gives a silent bug
re.match(pattern, s)A match object or NoneOnly worth it for patterns, not fixed text

6. Routing Chat Commands by Prefix

A chat bot treats messages that start with a slash as commands. The startswith() check routes the message, and partition() splits the command name from its arguments in one call.

def parse(message):
    if not message.startswith("/"):
        return None, message
    command, _, args = message[1:].partition(" ")
    return command.lower(), args

r1 = parse("/remind 10m tea")     # ('remind', '10m tea')
r2 = parse("/HELP")               # ('help', '')
r3 = parse("hello there")         # (None, 'hello there')

The same pattern works for any line-based protocol, such as reading commands from a file or a socket, where a prefix decides how the rest of the line is handled.

7. Prefix Check Questions

A plain startswith() call stops being enough once the prefix is a pattern or the data is bytes.

7.1. Does startswith() work with bytes?

Yes. A bytes object has its own startswith(), so a file signature check reads data.startswith(b”%PDF”). The prefix must also be bytes.

7.2. How do we check whether a string starts with a number?

We test the first character with isdigit(). The slice s[:1] returns an empty string instead of raising IndexError when s is empty.

starts_num = "3 apples"[:1].isdigit()    # True
empty_ok = ""[:1].isdigit()               # False

7.3. When should we use a regular expression instead?

When the prefix is a pattern rather than fixed text, such as “two letters followed by a dash”, re.match(r”[A-Z]{2}-“, s) is the right tool. For fixed text, startswith() is shorter and faster.

8. Conclusion

For log filters and config readers, startswith() with a tuple of prefixes is shorter and safer than slicing. We normalize the line with lower() or lstrip() before the check, and we switch to removeprefix() when we need the rest of the text.

9. 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.