4.3 String Inspection and Classification Methods
Key Takeaways
str.find()andstr.rfind()return-1when a target substring is missing, whereasstr.index()andstr.rindex()raise aValueError.str.count(sub, start, end)counts non-overlapping occurrences of a substring, and an empty substring arguments.count('')evaluates tolen(s) + 1.startswith()andendswith()verify boundary substrings and accept a tuple of candidate prefixes or suffixes for multi-pattern evaluation.Character classification methods (
isalpha(),isdigit(),isdecimal(),isnumeric(),isalnum(),isspace(),islower(),isupper(),istitle()) return boolean status flags based on Unicode properties.All string classification predicate methods return
Falsewhen invoked on an empty string (""), as they strictly require at least one qualifying character.
String Inspection and Classification Methods
Python provides a comprehensive suite of built-in string methods designed to search, inspect, count, and classify textual data. Mastering their specific return types, boundary parameters, and exception handling is essential for the PCAP certification.
1. Substring Searching: find() vs. index()
Python offers four primary methods to locate the position of a substring within a string:
+-------------+----------------------+-----------------------+
| Direction | Returns -1 on Miss | Raises ValueError |
+-------------+----------------------+-----------------------+
| Left-to-Right | str.find(sub) | str.index(sub) |
| Right-to-Left | str.rfind(sub) | str.rindex(sub) |
+-------------+----------------------+-----------------------+
Method Signatures
All four methods share identical parameter structures:
startandendinterpret search bounds identically to slice syntax[start:end].- The index returned is always relative to the start of the entire original string, never relative to
start.
text = "banana"
# Left-to-right searching
print(text.find("an")) # 1 (first 'an' begins at index 1)
print(text.index("an")) # 1
# Right-to-left searching
print(text.rfind("an")) # 3 (last 'an' begins at index 3)
print(text.rindex("an")) # 3
# Searching with slice boundaries [2:5]
print(text.find("an", 2, 5)) # 3
The Critical Difference: Missing Substring Behavior
The single most tested distinction on the PCAP exam is how these methods handle missing substrings:
text = "developer"
# find() and rfind() return -1 when the substring is absent
print(text.find("xyz")) # -1
print(text.rfind("xyz")) # -1
# index() and rindex() raise ValueError when the substring is absent
try:
text.index("xyz")
except ValueError as err:
print(f"Caught: {err}") # Caught: substring not found
2. Counting Occurrences: count()
The count() method returns the number of non-overlapping occurrences of a substring within an optional slice range [start:end]:
The Non-Overlapping Rule
Matches are consumed from left to right. Characters inside an identified match cannot participate in subsequent matches:
# In 'aaaa', non-overlapping pairs are indices 0-1 and 2-3
print("aaaa".count("aa")) # 2 (not 3!)
# In 'banana', matches for 'ana' occur at index 1; remaining 'na' does not match
print("banana".count("ana")) # 1
Edge Cases with count()
- Empty Substring (
""): Returnslen(s) + 1(the number of zero-width positions before, between, and after characters):print("dog".count("")) # 4 (len("dog") + 1) print("".count("")) # 1 - Substring Not Found: Returns
0without raising any exceptions.
3. Prefix and Suffix Verification: startswith() and endswith()
The startswith() and endswith() methods test whether a string begins or ends with a specific sequence:
filename = "project_report_2026.pdf"
print(filename.startswith("project")) # True
print(filename.endswith(".pdf")) # True
print(filename.startswith("Report")) # False (case-sensitive)
Passing a Tuple of Candidates
Both methods accept a tuple of strings to check against multiple possibilities simultaneously:
url = "https://openedg.org"
# Check multiple prefixes with a tuple
print(url.startswith(("http://", "https://"))) # True
# Check multiple file extensions
image_file = "header_logo.png"
valid_extensions = (".jpg", ".jpeg", ".png", ".webp")
print(image_file.endswith(valid_extensions)) # True
Exam Trap: Passing a
listorsetinstead of atupleraises aTypeError:# Raises TypeError: tuple for startswith -- or str -- required, not list filename.endswith([".pdf", ".txt"])
4. Character Classification and Predicate Methods
Python provides a robust set of boolean predicate methods to classify the characters within a string. All of these methods return bool (True or False).
| Method | Condition for True | Example Returning True | Example Returning False |
|---|---|---|---|
isalpha() | All characters are alphabetic letters (A-Z, a-z, Unicode letters) | "Python" | "Python3", "Hello World" |
isalnum() | All characters are alphanumeric (letters or digits) | "Python3" | "Python 3", "item-1" |
isdecimal() | All characters are base-10 digits (0-9) | "2026" | "20.26", "2²" |
isdigit() | All characters are digits (includes superscripts/subscripts) | "2026", "²" | "20.26", "½" |
isnumeric() | All characters are numeric (includes fractions, Roman numerals) | "2026", "½" | "20.26", "abc" |
isspace() | All characters are whitespace (' ', \t, \n, \r, \f, \v) | " \t\n " | "", " a " |
islower() | At least one cased char, and all cased chars are lowercase | "python 3.10" | "Python", "123" |
isupper() | At least one cased char, and all cased chars are uppercase | "PCAP 2026" | "Pcap", "123" |
istitle() | String is titlecased (words start uppercase followed by lowercase) | "Hello World 2" | "Hello world", "HELLO" |
isidentifier() | String is a valid Python variable/identifier name | "var_1", "_test" | "2var", "my-var" |
isprintable() | All characters are printable (or string is empty) | "Hello 123" | "Hello\nWorld" |
5. The Digit Hierarchy: isdecimal() vs. isdigit() vs. isnumeric()
Understanding the exact Unicode subset relationship between digit methods is frequently tested:
# 1. Standard ASCII Digits ('0'-'9')
s_ascii = "123"
print(s_ascii.isdecimal(), s_ascii.isdigit(), s_ascii.isnumeric())
# Output: True True True
# 2. Superscript / Subscript digits ('²')
s_super = "2\u00b2" # '2²'
print(s_super.isdecimal(), s_super.isdigit(), s_super.isnumeric())
# Output: False True True
# 3. Vulgar Fractions ('½')
s_frac = "\u00bd" # '½'
print(s_frac.isdecimal(), s_frac.isdigit(), s_frac.isnumeric())
# Output: False False True
6. Case Predicate Rules and Uncased Characters
The case testing methods (islower(), isupper(), and istitle()) ignore non-cased characters (digits, symbols, whitespace, punctuation), provided there is at least one cased character in the string:
# Non-cased characters are ignored if a cased letter exists
print("python_3.10!".islower()) # True ('p', 'y', 't', 'h', 'o', 'n' are lowercase)
print("HTTP_404_NOT_FOUND".isupper()) # True
# If NO cased characters exist, islower() and isupper() return False
print("12345!".islower()) # False
print("12345!".isupper()) # False
print(" ".islower()) # False
7. The Empty String Rule
A critical rule for PCAP candidates to memorize:
The Universal False Rule on Empty Strings: Every character classification method (
isalpha(),isdigit(),isdecimal(),isnumeric(),isalnum(),isspace(),islower(),isupper(),istitle()) returnsFalsewhen invoked on an empty string"".Reason: All of these methods strictly require a string length of at least 1 character () satisfying the condition.
(Exception:
"".isprintable()evaluates toTrue).
What happens when executing the following Python code snippet?
text = "automation"
pos = text.find("xyz")
print(pos)
It prints -1.
It raises a ValueError: substring not found.
It prints None.
It raises an IndexError.
What is the output of the following occurrence count?
print("banana".count("ana"))
2
1
0
3
Consider the following expressions evaluated on empty and mixed strings:
print("".isalpha(), "123a".isdigit(), "Python 3".islower())
What is printed?
True False False
False True False
False False False
False False True
What exception, if any, is raised by the following code?
filename = "report.pdf"
print(filename.endswith([".pdf", ".docx"]))
ValueError: substring not found
AttributeError: 'str' object has no attribute 'endswith'
No exception; it prints True
TypeError: endswith first arg must be str or a tuple of str, not list
Sections you finish are checked off in the contents.