Skip to main content

String indexing & slicing

Level 1: Level 1: Foundationseasy9 minstringsindexingslicinglen

Reach into text by position, take slices, and measure length.

Why reaching into text by position matters

Almost every parsing task starts with position. You pull a fixed-width field out of a log line, strip a known bracket or prefix off an ID, grab the last four characters of an order number, or read a file extension off the end of a name. Before you reach for fancy string methods or regular expressions, indexing and slicing are the cheapest, most predictable way to get at part of a string. Get these solid and half of "clean up this messy text" work becomes trivial.

A string is an indexed sequence

A Python string is an ordered sequence of characters. Every character has a position, called an index, counted from 0 at the front. You can also count from the back with negative indices, where -1 is the last character:

Table
Two rulers over the same six characters. Counting from the front starts at 0, which is why the last index is 5 and not 6; counting from the back starts at -1, because -0 and 0 would be the same number.
Countingpython
From the front012345
From the back-6-5-4-3-2-1
Two rulers over the same six characters. Counting from the front starts at 0, which is why the last index is 5 and not 6; counting from the back starts at -1, because -0 and 0 would be the same number.

Reach in with square brackets, and use len() to count characters:

word = "python"
word[0]    # "p"   first character
word[-1]   # "n"   last character
len(word)  # 6     number of characters

To build the first-and-last string you will need in the Apply, you combine two indexed characters with +: word[0] + word[-1] gives "pn". For a one-character string like "a", both word[0] and word[-1] point at the same character, so you get "aa".

Slicing: half-open ranges

Check yourself
word is the string python. What does word[0:3] give you?

text[start:stop] returns a slice, a new string running from start up to but not including stop:

word[0:3]   # "pyt"   indices 0, 1, 2
word[2:]    # "thon"  from 2 to the end
word[:2]    # "py"    start up to index 2
word[1:-1]  # "ytho"  drop the first and last character

That word[1:-1] pattern is exactly what the Practice needs. text[1:-1] starts at the second character and stops just before the last, so "[hi]" becomes "hi".

Slicing with a step

A slice takes an optional third number, the step: text[start:stop:step]. The step sets how far to jump between characters, so word[::2] keeps every second character ("pto" from "python"). Leaving start and stop empty runs across the whole string.

A negative step walks backward, so the idiom text[::-1] reverses a string by stepping from the end to the start:

word[::2]    # "pto"     every second character
word[::-1]   # "nohtyp"  the whole string, reversed
"abc"[::-1]  # "cba"

Reversing with [::-1] is the idiomatic way to test a palindrome: text == text[::-1].

Check yourself
word is the string python. You write word[0] = 'P'. What happens?

Strings are immutable

You cannot change a character in place. word[0] = "P" raises TypeError. Every operation that "modifies" a string actually builds a new string and leaves the original untouched. That is why slicing returns a fresh value instead of editing word.

Pitfalls

Check yourself
text is the two-character string hi. Compare what text[5] does with what text[0:5] does.
  • Indexing out of range raises, slicing does not. "hi"[5] raises IndexError, but "hi"[0:5] quietly clamps and returns "hi". Slicing never errors on out-of-range bounds; single-character indexing does.
  • The empty string has no characters. ""[0] raises IndexError, so first_and_last("") would blow up. Both exercises assume at least one character, but in real code you check for empty input first.
  • A short slice can go empty, not error. "ab"[1:-1] is "", because start (1) is not before stop (-1, meaning index 1). No exception, just an empty result.

Interview nuance: Python slicing uses a half-open interval [start, stop). This is not a quirk; it makes the boundary math clean. With non-negative, in-range bounds where start is at or before stop, the slice length is exactly stop - start, and for any index i, s[:i] + s[i:] == s reconstructs the original with no overlap and no gap. Interviewers lean on this half-open convention to check whether you reason about boundaries correctly, the same off-by-one discipline that shows up in array windows and pagination.

Worked example (Python)
word = "python"
print(word[0])     # p
print(word[-1])    # n
print(word[1:-1])  # ytho
print(len(word))   # 6

Apply

Your turn

The task this lesson builds to.

Implement first_and_last(text): return a 2-character string made of the first and last characters of text.

For "python" return "pn". (A one-character string like "a" returns "aa".)

3 hints and 4 automated checks are waiting in the workspace.

Practice

Make it stick

A second problem on the same idea, so it survives past today.

Implement without_ends(text): return text with its first and last characters removed.

For "python" return "ytho". For "[hi]" return "hi".

2 hints and 4 automated checks are waiting in the workspace.