Python Part I · Module 4 · Strings
split(): Breaking a Line Into Fields
A line of output usually contains several separate pieces of information with something between them — spaces in a status line, commas in an exported table. Taking that line apart is the single most useful text operation there is, and Chapter 4.5 already showed that slicing by column number only works when the columns never move. split() is the tool for the far more common case where the pieces are separated rather than aligned. It is easy to use and has exactly one subtlety worth real attention: calling it with no argument and calling it with a single space look equivalent and are not, and the difference only becomes visible on text whose spacing is uneven — which is to say, on real text.
Foundation13 min readPythonPart IFundamentalsStringsParsing
Part I · Module 4 · Chapter 4.8 · split(): Breaking a Line Into Fields
1. One Line, Several Pieces
Here is a line of the kind a tool writes at the end of a run. It holds four separate pieces of information:
line = "axi_smoke 4210 PASS 182.4"A test name, a seed, a status and a runtime. You could reach them with the slices from Chapter 4.5, and it would work right up until a test name got longer and every boundary moved.
What you want is to cut the line wherever the spaces are. That is split():
line = "axi_smoke 4210 PASS 182.4"
fields = line.split()
print(fields)['axi_smoke', '4210', 'PASS', '182.4']One string went in. Four strings came out, with the spaces consumed as the cut points rather than kept.
2. What Came Back
Those square brackets are new, and they need exactly two sentences of explanation and no more.
Python has returned the pieces as a single value that holds several strings in order. That kind of value is called a list, and Module 5 is devoted to it — how to build one, change one, sort one and work through one.
For this chapter you need only two facts about it.
First, the pieces are in order — the same order they appeared in the line.
Second, the square-bracket notation from Chapter 4.4 reaches one of them, counting from zero in exactly the same way it did for characters:
line = "axi_smoke 4210 PASS 182.4"
fields = line.split()
print(fields[0])
print(fields[2])
print(fields[-1])axi_smoke
PASS
182.4fields[2] is the third piece, because counting starts at zero. fields[-1] is the last, exactly as -1 was the last character of a string. You already know this notation; only the thing it is applied to is new.
And len() counts the pieces, just as it counted characters:
line = "axi_smoke 4210 PASS 182.4"
print(len(line.split()))4That is Chapter 4.6's promise paying off — len() is a function precisely so that it works on this without you learning anything new.
One more thing worth confirming — each piece is an ordinary string, including the ones that look like numbers:
line = "axi_smoke 4210 PASS 182.4"
fields = line.split()
print(type(fields[1]))
print(repr(fields[1]))<class 'str'>
'4210''4210' in quotes, str as the type. Splitting text produces text. If you want to do arithmetic on that seed you must convert it with int() from Chapter 2.11 — which is exactly the point Chapter 2.9 made about "4210" not being 4210, arriving now with a practical consequence.
3. Splitting on Something Specific
Pass a separator and split cuts there instead:
record = "axi_smoke,4210,PASS,182.4"
print(record.split(","))['axi_smoke', '4210', 'PASS', '182.4']Same four fields, taken from a comma-separated line. The separator can be more than one character, which is occasionally useful:
print("a -> b -> c".split(" -> "))['a', 'b', 'c']The whole four-character sequence " -> " was the cut point, and it disappeared into the cuts.
4. split() and split(" ") Are Not the Same
This is the section that matters. On the original line the two calls look interchangeable, and on that line they are. On real text they are not.
Here is a line whose columns have been padded to line up — completely normal in tool output:
messy = "axi_smoke 4210 PASS"
print(messy.split())
print(messy.split(" "))['axi_smoke', '4210', 'PASS']
['axi_smoke', '', '', '', '4210', '', '', 'PASS']Three fields, or eight. Same string, two calls that differ by two characters.
The reason is that they are genuinely different operations:
split()with no argument means split on whitespace, and it treats a whole run of whitespace as one separator. Four spaces in a row is one cut point, not four.split(" ")with an explicit single space means split at every single space character. Four spaces in a row are four separators, and between the first and second there is nothing — so Python correctly reports an empty string as the field that lay between them.
Python is not being unhelpful in the second case. You asked it to cut at every space, and it did.
The no-argument form has two further conveniences, both consequences of the same rule.
It handles every kind of whitespace, not just spaces:
mixed = "a\tb\n c"
print(mixed.split())['a', 'b', 'c']Tabs and newlines are whitespace, so they are cut points too. You do not have to know which kind separates your fields.
It ignores whitespace at the ends rather than producing empty fields there:
print(" a b ".split())
print(" a b ".split(" "))['a', 'b']
['', '', 'a', 'b', '', '']Which gives a genuinely useful result: for whitespace-separated text you do not even need to strip first.
raw = " axi_smoke 4210 PASS \n"
print(raw.split())['axi_smoke', '4210', 'PASS']The leading spaces, the trailing spaces and the newline from Chapter 4.7 all vanished on their own, because they are whitespace and split() with no argument treats them as separators rather than content.
5. When the Separator Is Not There
split never fails for not finding its separator. It gives back one piece — the whole original string:
print("PASS".split(","))
print(len("PASS".split(",")))['PASS']
1That is the consistent answer: cutting a string in zero places leaves one piece. It is also a thing to be careful about, because a line in an unexpected format gives you a single field rather than an error, and a script that assumes four fields will then fail somewhere further along.
6. Empty Fields Are Real Fields
With an explicit separator, two separators next to each other have nothing between them, and that nothing is reported:
print("a,,b".split(","))
print("a,b,".split(","))
print(",a".split(","))['a', '', 'b']
['a', 'b', '']
['', 'a']This is correct and useful. In a comma-separated table an empty field means "this column had no value", and that is different from the column not being there — so split(",") preserves it.
The boundary case follows the same two rules and is worth seeing side by side:
print("".split())
print("".split(","))[]
['']An empty string split on whitespace gives no pieces at all: there was no non-whitespace content, so there are no fields. An empty string split on a comma gives one empty piece: there are no commas, so there is one field, and that field happens to be empty.
Both answers follow from Section 4. They only look inconsistent if you think of the two calls as the same operation.
7. Broken on Purpose
Reaching a field that is not there. This is the same off-by-one as Chapter 4.4, with a slightly different message:
fields = "a b".split()
print(fields[5])IndexError: list index out of rangelist index out of range rather than string index out of range, because the thing being indexed is now a list. The diagnosis is identical: check the index against len(fields).
Splitting on nothing. An empty separator has no sensible meaning — there is no way to cut "at every empty place" — and Python says so rather than guessing:
print("abc".split(""))ValueError: empty separatorThis is a ValueError, not a TypeError: the argument was the right type, a string, but not a usable value. If you actually want the individual characters of a string, indexing from Chapter 4.4 is the tool, and Module 10 will give you a way to work through all of them.
8. Predict, Run, Observe
Predict all five before reading on. Two are the traps from this chapter.
row = "reg_rw FAIL 91.2"
print(row.split())
print(len(row.split()))
print(row.split(" "))
print(row.split(","))
print("a,,b".split(","))The verified output:
['reg_rw', 'FAIL', '91.2']
3
['reg_rw', '', '', 'FAIL', '', '', '91.2']
['reg_rw FAIL 91.2']
['a', '', 'b']The third gives seven pieces because there are six separate spaces, and the gaps between adjacent ones are empty fields. The fourth gives one piece, unchanged, because there is no comma in the line to cut at — not an error, just nothing to do.
If you predicted three fields for the third line, re-read Section 4. That prediction is exactly the bug the callout warns about, and it is the kind that passes every test you write by hand and fails on the first real file.
9. Exercises
Exercise 1 — split and reach. For line = "smoke 7 PASS", write the expressions that produce: the status word, the seed, the first field, and the number of fields. Then say what type the seed is.
Exercise 2 — predict the count. Without running anything, say how many pieces each produces, then verify:
(a) "a b c".split() (b) "a b".split() (c) "a b".split(" ") (d) "a,b,".split(",") (e) "abc".split(",") (f) "".split() (g) "".split(",")
Exercise 3 — find the bug. This works on the author's example line and breaks on a real one. Explain what happens when two spaces appear, and change one thing to fix it:
line = "axi_smoke 4210 PASS"
fields = line.split(" ")
print(fields[1])Exercise 4 — the trailing newline. Predict the last field of each, then verify. Say which of the two calls needs a strip() first and why:
raw = "a,b,c\n"
print(raw.split(","))
print(raw.split())Exercise 5 — the wrong format. A line arrives as "axi_smoke;4210;PASS" but the script splits on commas. Say exactly what the script gets, why it does not raise an error, and where the failure will eventually appear.
Exercise 6 — convert a field. Given line = "smoke 4210 PASS", write an expression that produces the seed as a number rather than text, and one that proves it is a number. Name the chapter that taught you the conversion.
Exercise 7 — explain the asymmetry. In two or three sentences, explain why "".split() gives no pieces while "".split(",") gives one empty piece. Your answer should refer to the rule in Section 4, not to the examples.
10. Summary
line.split()breaks one string into its separate fields, returning them in order.- It returns a list. Module 5 owns lists; here you need only that the pieces are in order and reachable by number.
fields[0]is the first piece,fields[-1]the last — the same notation as characters in Chapter 4.4, andlen()counts the pieces.- Every piece is a string, including the ones that look like numbers. Convert with
int()orfloat()if you need arithmetic. split()with no argument splits on whitespace and treats a run of it as one separator. This is almost always the call you want.split(" ")splits at every single space, so uneven spacing produces empty fields."a b".split(" ")has five pieces.split()also handles tabs and newlines and ignores whitespace at the ends, so whitespace-separated text needs nostrip()first.split(",")does.- A missing separator is not an error. You get one piece: the whole string.
- Empty fields are preserved with an explicit separator, because an empty field is real information.
"".split()is no pieces;"".split(",")is one empty piece. Both follow from the rule above.fields[5]on a three-field line isIndexError: list index out of range, andsplit("")isValueError: empty separator.
Taking a line apart is half the job. The next chapter puts one back together.
Where this fits
Part of the Python curriculum.
