The str.rsplit([sep[, maxsplit]]) method breaks a string into a list of substring tokens, evaluating delimiters from right to left when a limited maxsplit count is specified.
Directional Splitting Rule: When maxsplit is omitted or set to -1, rsplit() behaves identically to str.split(). The distinction emerges when limiting splits: rsplit() splits from the rightmost delimiter first, preserving the un-split remainder at index 0.
The standard CPython signature for str.rsplit() is:
str.rsplit(sep=None, maxsplit=-1)
| Parameter | Type | Default | Behavior & Description |
|---|---|---|---|
sep |
str | None |
None |
Delimiter string. If None, consecutive whitespace characters (spaces, tabs, newlines) are grouped together as single boundaries. |
maxsplit |
int |
-1 |
Maximum number of splits to perform. If -1 or omitted, all possible splits occur. When ≥ 0, at most maxsplit splits are performed from the right. |
| Return Value | list[str] |
— | A new list containing at most maxsplit + 1 elements. Original string remains unmodified (immutable). |
The directional difference between split() and rsplit() only manifests when maxsplit limits the operation. When you limit splits, split() isolates leading tokens, while rsplit() isolates trailing tokens.
path = "usr/local/bin/python"
# split() consumes the first delimiter from the left
left_split = path.split("/", 1)
print("split(maxsplit=1): ", left_split)
# Output: ['usr', 'local/bin/python']
# rsplit() consumes the first delimiter from the right
right_split = path.rsplit("/", 1)
print("rsplit(maxsplit=1):", right_split)
# Output: ['usr/local/bin', 'python']
Notice that in both cases, the resulting list contains maxsplit + 1 = 2 elements, and reading the elements from left to right preserves the original substring sequence.
Just like standard split(), rsplit() exhibits two distinct parsing algorithms depending on whether sep is None or an explicit string:
sep=None): Consecutive whitespace characters (spaces, tabs,
, ) are consolidated into single boundaries. Trailing whitespace is stripped before right-hand splitting starts. Unsplit sections preserve their inner spacing until consumed by subsequent splits.sep=" " or sep=","): Delimiters are matched literally. Adjacent delimiters produce empty string tokens ("").record = " apple banana cherry "
# Default whitespace grouping from right (maxsplit=1)
clean_tokens = record.rsplit(None, 1)
print("sep=None: ", clean_tokens)
# Output: [' apple banana', 'cherry']
# Explicit single space matching from right (maxsplit=1)
raw_tokens = record.rsplit(" ", 1)
print("sep=' ': ", raw_tokens)
# Output: [' apple banana cherry ', '']
Understanding when to choose rsplit() over split() or rpartition() depends on the number of tokens required and whether the delimiter needs to be retained:
| Method | Return Type | Split Direction | Max Splits Allowed | Includes Separator? | Behavior if sep Missing |
|---|---|---|---|---|---|
str.rsplit(sep, n) |
list[str] |
Right → Left | Configurable (n) |
No | Returns [original_str] |
str.split(sep, n) |
list[str] |
Left → Right | Configurable (n) |
No | Returns [original_str] |
str.rpartition(sep) |
tuple[str, str, str] |
Right → Left | Always exactly 1 | Yes (middle item) | Returns ('', '', original_str) |
re.split(pattern, s) |
list[str] |
Left → Right | Configurable | Only if captured () |
Returns [original_str] |
Here are practical production patterns where str.rsplit() simplifies string manipulation without requiring external libraries or regular expressions.
Quickly separate a Unix or URL path into the parent folder and file name by performing a single right-hand split:
def split_path(filepath: str) -> tuple[str, str]:
parts = filepath.rsplit("/", 1)
if len(parts) == 1:
return "", parts[0]
return parts[0], parts[1]
directory, filename = split_path("/var/log/nginx/access.log")
print("Dir: ", directory) # /var/log/nginx
print("File:", filename) # access.log
Modern international email specifications allow quotes and special symbols inside the local-part, but the final @ always designates the domain. Using rsplit('@', 1) safely isolates the true domain host:
def parse_email(email: str) -> tuple[str, str]:
tokens = email.rsplit("@", 1)
if len(tokens) != 2:
raise ValueError(f"Invalid email format: {email}")
return tokens[0], tokens[1]
user, domain = parse_email("developer.support@plus2net.com")
print("Username:", user)
print("Domain: ", domain)
When config values themselves contain delimiters (such as connection strings or equations), right-to-left splitting allows extracting trailing options without breaking earlier tokens:
config_entry = "database_url=postgres://user:pass@host:5432/db?ssl=true"
# Separate the key from everything else on the right
key, val = config_entry.split("=", 1)
# Separate trailing parameter from the base url
base, last_param = val.rsplit("?", 1)
print("Key: ", key)
print("Base URL: ", base)
print("Parameters:", last_param)
Passing an empty string "" as the separator raises ValueError: empty separator. To split every character into individual elements, use list(s) instead.
try:
"hello".rsplit("")
except ValueError as err:
print("Error caught:", err) # ValueError: empty separator
# Correct approach to obtain individual characters:
chars = list("hello")
print("Characters:", chars) # ['h', 'e', 'l', 'l', 'o']
A common misconception is that text.rsplit(',') returns tokens in reverse order. It does not. The returned list has identical ordering and contents as text.split(','). Direction only changes the allocation of non-split content when maxsplit is constrained.
Execute this production test harness to verify right-to-left splitting behavior, error handling, and parameter bounds:
class RightSplitVerifier:
@staticmethod
def extract_suffix(target: str, delim: str) -> str:
tokens = target.rsplit(delim, 1)
return tokens[-1] if len(tokens) > 1 else ""
@staticmethod
def tail_n_tokens(text: str, delim: str, count: int) -> list[str]:
return text.rsplit(delim, count)
# Self-checking unit assertions
verifier = RightSplitVerifier()
# Test 1: Suffix extraction
assert verifier.extract_suffix("archive.tar.gz", ".") == "gz"
assert verifier.extract_suffix("README", ".") == ""
# Test 2: Directional maxsplit comparison
sample = "one:two:three:four"
assert sample.rsplit(":", 1) == ["one:two:three", "four"]
assert sample.split(":", 1) == ["one", "two:three:four"]
# Test 3: Unconstrained parity between split and rsplit
assert sample.rsplit(":") == sample.split(":")
# Test 4: Default whitespace handling (trailing stripped, internal preserved)
ws_test = "alpha beta gamma"
assert ws_test.rsplit(None, 1) == ["alpha beta", "gamma"]
ws_padded = " alpha beta gamma "
assert ws_padded.rsplit(None, 1) == [" alpha beta", "gamma"]
assert ws_padded.rsplit(None) == ["alpha", "beta", "gamma"]
print("All str.rsplit() unit assertions passed successfully!")
Open in Google Colab View on GitHub
Run all right-to-left string partitioning examples interactively, contrast rsplit() with split() and rpartition(), test whitespace consolidation algorithms, and parse config files in Google Colab.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.