Mastering String Slicing

Introduction: From One Character to a Whole Chunk

Welcome back! We know how to reach any single character inside a string. Useful as that is, real text work rarely stops at one character. We usually want a piece of text: the name part of a filename, its final few characters, or the year buried inside a timestamp.

Python's tool for that job is slicing, written as text[start:stop:step]. Same square brackets as before, just with colons separating up to three numbers. Our running example is a filename:

Python
filename = "report_2024.csv"
Characterreport_2024.csv
Index01234567891011121314
Negative-15-14-13-12-11-10-9-8-7-6-5-4-3-2-1

Basic Slice Syntax: [start:stop]

Let's start with the two-number form, asking for characters from position 0 up to position 6:

Python
filename = "report_2024.csv"

# [start:stop] includes start, excludes stop
print("Characters 0-5:", filename[0:6])

The single most important rule of slicing is that start is included and stop is excluded. So filename[0:6] collects indices 0 through 5, which spell "report"; index 6, the underscore, stays out. A handy side effect is that the length of the result equals stop - start — here, six characters.

Two more details: a slice builds a new string and leaves filename untouched, and a backward range such as filename[4:2] simply gives an empty string "" rather than an error.

text
Characters 0-5: report

Spelling Out Both Bounds

The two-number form really shines when the piece we want sits in the middle, with text on both sides. The year in our filename is a good example: it starts at index 7 and we want four characters, so we stop at 7 + 4 = 11.

Python
# Both bounds spelled out to take a piece from the middle
print("Year:", filename[7:11])

This collects indices 7, 8, 9, and 10 — the characters 2, 0, 2, 4 — giving "2024". Note how the exclusive stop works for us here: 11 is the index of the dot, and naming it as the stop keeps it out of the result. A useful way to picture it is that the numbers mark the gaps between characters rather than the characters themselves, so [7:11] means "everything between gap 7 and gap 11."

text
Year: 2024

Omitting Bounds to Reach the Edges

Writing 0 as the start feels redundant, and Python agrees: either bound can be left out, and it snaps to the nearest edge of the string. No start means "from the very beginning," no stop means "through the very end."

Python
# Omitting a bound runs to the edge of the string
print("Prefix:", filename[:6])
print("Suffix:", filename[7:])

This gives us the classic prefix/suffix pair:

  • filename[:6] is identical to filename[0:6], so we get the prefix "report" with less typing.
  • filename[7:] starts at index 7, the 2 in 2024, and runs all the way to the final v, producing "2024.csv".

Leaving out both bounds, as in filename[:], asks for everything: a full copy of the string.

text
Prefix: report
Suffix: 2024.csv

Negative Indices Inside Slices

As you may recall from Unit 1, negative indices count backward from the right, with -1 as the last character. Those same numbers work as slice bounds, which makes end-of-string work delightfully short:

Python
# Negative indices in slices count from the end
print("Last three:", filename[-3:])

filename[-3:] starts three characters from the end and runs through the end, giving "csv". Two reusable patterns are worth memorizing:

  • text[-N:] means "the last N characters."
  • text[:-N] means "everything except the last N characters," so filename[:-4] gives "report_2024".

Neither form needs len() first, so the same expression works for "a.csv" or a filename with fifty characters.

An honest caveat about file extensions. For this filename, the last three characters happen to be the extension, csv. But that is a fact about our example, not a general rule: "script.py" has a two-character extension, "photo.jpeg" has four, "README" has none at all, and "data.tar.gz" has two suffixes stacked. [-3:] would quietly return the wrong text in every one of those cases. Real code finds the dot instead of assuming a width — in Unit 4 we will meet find(), which locates a character for us, and Python's standard library offers pathlib.Path(filename).suffix for exactly this job. For now, treat [-3:] as "the last three characters," which is all it really promises.

text
Last three: csv

Adding a Step: [start:stop:step]

Now for the third slot in text[start:stop:step]. The step value tells Python how far to jump after taking each character; it defaults to 1, which is why every slice so far picked up neighbours. Setting it to 2 takes every second character instead:

Python
# A step selects every nth character
print("Every second char:", filename[::2])

Both bounds are omitted, so we walk the whole string, and the step of 2 visits indices 0, 2, 4, 6, 8, 10, 12, and 14. Reading those off the table gives r, p, r, _, 0, 4, c, v, joined into "rpr_04cv". A step of 3 would visit 0, 3, 6, and so on; any positive whole number works.

text
Every second char: rpr_04cv

Reversing with a Negative Step

A step can also be negative, which flips the direction of travel: Python walks the string from right to left. This turns string reversal into a single expression:

Python
# A negative step reverses the string
print("Reversed:", filename[::-1])

Starting from the last character, v, and stepping backward one position at a time, we collect every character in reverse order, ending on the leading r. Here is the gotcha worth remembering: with a negative step the default bounds flip too, so an omitted start means "the end of the string" and an omitted stop means "past the beginning."

That is why [::-1] is the reliable reversal idiom, while a hopeful guess such as filename[0:15:-1] returns an empty string — we would be asking Python to move left from index 0, and there is nothing there.

text
Reversed: vsc.4202_troper

Slice Patterns Cheat Sheet

Most day-to-day slicing comes down to a handful of shapes:

PatternMeaningExample on filename
[a:b]From a up to, but not including, b[7:11] gives "2024"
[:n]The first n characters[:6] gives "report"
[n:]Everything from n to the end[7:] gives "2024.csv"
[-n:]The last n characters[-3:] gives "csv"
[:-n]Everything except the last n[:-4] gives "report_2024"
[::k]Every k-th character[::2] gives "rpr_04cv"
[::-1]The whole string reversed"vsc.4202_troper"

Recognizing these shapes on sight is the real goal; the rest is filling in numbers that fit the task at hand.

Conclusion and Next Steps

One more comforting property before we practise: unlike indexing, slicing never raises an out-of-range error. It quietly clips to what exists, so filename[:500] returns the whole string rather than crashing, and even an empty string survives every slice in the table above.

In Unit 3 we shift from carving text apart to reshaping it with string methods such as upper, strip, and replace. Time to slice!

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal