Python: Split a String into a List (split, re.split, csv, shlex)

Call text.split() to split a string into a list of words on any run of whitespace, or text.split(",") to split on an exact separator. For several different delimiters use re.split(), for individual characters use list(text), and for quoted fields use the csv or shlex modules.
All examples were run on Python 3.13; the behaviour shown has been stable throughout Python 3.
str.split() with and without a separator
str.split(sep=None, maxsplit=-1) has two distinct modes depending on whether you pass sep.
line = " alpha beta\tgamma\n delta "
print(line.split())
csv_row = "red,green,,blue"
print(csv_row.split(","))
print("a--b--c".split("--"))
['alpha', 'beta', 'gamma', 'delta']
['red', 'green', '', 'blue']
['a', 'b', 'c']
- No argument (or
None): splits on runs of any whitespace (spaces, tabs, newlines, and other Unicode whitespace) and discards leading and trailing whitespace. You never get empty strings. - Explicit
sep: splits on that exact string, which may be several characters long. Consecutive separators produce empty strings, because each occurrence marks a field boundary.
split() versus split(" ")
This difference catches people regularly:
s = "a b c "
print(s.split())
print(s.split(" "))
print("".split())
print("".split(","))
print(" ".split())
['a', 'b', 'c']
['a', '', 'b', 'c', '']
[]
['']
[]
split(" ") treats every single space as a separator, so double spaces and a trailing space create empty items, and tabs are not split at all. Splitting an empty string with an explicit separator returns [''], a one-element list, not an empty one. If you are splitting human-entered text into words, you almost always want the no-argument form. Passing an empty separator, "abc".split(""), raises ValueError: empty separator.
Limiting splits: maxsplit, rsplit and partition
maxsplit caps the number of splits, leaving the remainder intact. rsplit does the same counting from the right.
log = "2026-10-24 12:00:01 ERROR disk full: /var is at 98%"
date, time, level, message = log.split(maxsplit=3)
print(level, "|", message)
path = "/srv/www/site/static/app.min.js"
print(path.rsplit("/", 1))
print("app.min.js".rsplit(".", 1))
print("key=value=more".split("=", 1))
print("a b c".partition(" "))
ERROR | disk full: /var is at 98%
['/srv/www/site/static', 'app.min.js']
['app.min', 'js']
['key', 'value=more']
('a', ' ', 'b c')
Without maxsplit, rsplit gives the same result as split; it only matters when you limit the count. str.partition(sep) and str.rpartition(sep) always return a 3-tuple (head, separator, tail), which is convenient for unpacking because it never raises if the separator is missing. For file paths, prefer pathlib.Path (.parent, .name, .suffix) over manual splitting.
Splitting lines: splitlines()
text = "first line\nsecond line\r\nthird line\n"
print(text.splitlines())
print(text.split("\n"))
print(text.splitlines(keepends=True))
['first line', 'second line', 'third line']
['first line', 'second line\r', 'third line', '']
['first line\n', 'second line\r\n', 'third line\n']
splitlines() recognises \n, \r\n, \r and several Unicode line boundaries, and it does not produce a trailing empty item for a final newline. split("\n") leaves stray \r characters on Windows-style text and adds an empty last element. Use splitlines() for text; for files, iterate over the file object directly instead of reading everything and splitting.
Multiple delimiters with re.split()
When fields can be separated by different characters, use re.split(pattern, string, maxsplit=0) with a character class:
import re
data = "apples, oranges;pears bananas|kiwis"
print(re.split(r"[,;|\s]+", data))
['apples', 'oranges', 'pears', 'bananas', 'kiwis']
The + makes a run of mixed delimiters (such as ", ") count as one boundary. Always use a raw string (r"...") for patterns.
Keeping the delimiters
If the pattern contains a capturing group, the matched delimiters are included in the result. Put the group around exactly what you want to keep:
print(re.split(r"(\s*[-+*/]\s*)", "3 + 4*2 - 1"))
print(re.split(r"\s*([-+*/])\s*", "3 + 4*2 - 1"))
['3', ' + ', '4', '*', '2', ' - ', '1']
['3', '+', '4', '*', '2', '-', '1']
To keep a delimiter attached to the preceding piece instead, split on a zero-width lookaround:
print(re.split(r"(?<=[.!?])\s+", "One. Two! Three? Four"))
print(re.split(r"(?=[A-Z])", "parseHttpResponseCode"))
['One.', 'Two!', 'Three?', 'Four']
['parse', 'Http', 'Response', 'Code']
Empty strings at the edges
print(re.split(r"\W+", "Hello, world!"))
print([t for t in re.split(r"\W+", "Hello, world!") if t])
print(re.findall(r"\w+", "Hello, world!"))
['Hello', 'world', '']
['Hello', 'world']
['Hello', 'world']
A delimiter at the start or end of the string yields an empty item. Filter it out, or flip the logic and use re.findall to match the tokens you want rather than the separators between them. In the re module, pass maxsplit as a keyword argument; passing it positionally is deprecated since Python 3.13.
Splitting into characters
print(list("héllo"))
print([int(d) for d in "2026"])
print(list(map(int, "10 20 30".split())))
['h', 'é', 'l', 'l', 'o']
[2, 0, 2, 6]
[10, 20, 30]
A string is an iterable of characters, so list(s) splits it into single code points. You usually do not need to: you can index and loop over a string directly. Note that "characters" here means Unicode code points; an emoji with a skin-tone modifier or a letter written with a combining accent can span several.
Quoted fields: use csv
Comma-separated data often contains commas inside quoted fields. split(",") breaks those apart; the csv module handles quoting and escaped quotes correctly:
import csv
row = 'Ada,"Lovelace, Countess",1815,"said ""hi"""'
print(row.split(","))
print(next(csv.reader([row])))
['Ada', '"Lovelace', ' Countess"', '1815', '"said ""hi"""']
['Ada', 'Lovelace, Countess', '1815', 'said "hi"']
csv.reader accepts any iterable of lines, including an open file (open it with newline=""). Use delimiter="\t" for TSV.
Shell-like splitting: shlex.split()
To split a command line the way a POSIX shell would, respecting quotes and backslash escapes, use shlex:
import shlex
cmd = 'grep -r "hello world" --include=*.py ./src'
print(cmd.split())
print(shlex.split(cmd))
print(shlex.join(["echo", "it's here"]))
['grep', '-r', '"hello', 'world"', '--include=*.py', './src']
['grep', '-r', 'hello world', '--include=*.py', './src']
echo 'it'"'"'s here'
The result can be passed straight to subprocess.run(args) without shell=True. shlex.join (Python 3.8+) is the inverse and quotes arguments safely.
Which method to use
| Input | Method |
|---|---|
| Words separated by any whitespace | s.split() |
| Fields with one fixed separator | s.split(sep) |
| Only the first / last N pieces | split(sep, n), rsplit(sep, n), partition |
| Lines of text | s.splitlines() |
| Several delimiters or patterns | re.split() or re.findall() |
| Individual characters | list(s) |
| CSV with quotes | csv.reader |
| Command lines | shlex.split() |
Troubleshooting
- Unexpected empty strings: you passed an explicit separator and the input has repeated or trailing separators. Use
split()without arguments, or filter with[x for x in parts if x]. - Whitespace around items after
split(","): strip each item,[p.strip() for p in s.split(",")], or split onr"\s*,\s*"withre. ValueError: too many values to unpack: the line has more fields than variables. Addmaxsplitor usepartition.AttributeError: 'list' object has no attribute 'split': you are callingspliton a list; split each element in a comprehension.- Special characters in
re.split: escape literal delimiters withre.escape(), e.g.re.split("|".join(map(re.escape, seps)), s).
Summary
s.split() splits on whitespace and never returns empty items; s.split(sep) splits on an exact string and preserves empty fields. Use maxsplit, rsplit or partition to limit splits, splitlines() for lines, re.split() for multiple delimiters (with a capturing group to keep them), list(s) for characters, and csv or shlex whenever quoting is involved.
PythonCount word occurrences
Count how often words appear in a Python list with list.count, collections.Counter, dict and defaultdict loops, normalization of case and punctuation, and pandas.
PythonCould not convert string to float
Why float() raises "could not convert string to float": empty strings, commas, currency symbols, N/A values, and how to fix them in Python and pandas.
DataUnicodeDecodeError in read_csv
Why pd.read_csv raises UnicodeDecodeError: 'utf-8' codec can't decode byte, and how to fix it with the right encoding, BOM handling and UTF-8 conversion.