String Indexing
Concepts covered: String Indexing
A string is an ordered sequence of characters, and each character sits at a numbered position called its index. Counting starts at 0. Writing text[i] reads the character at position i and returns it as a new string of length 1. An index is an offset, the number of characters you skip from the start to reach this one. The first character needs 0 skips, and the second needs 1.
text = "Python"
print(text[0])
print(text[1])
print(text[5])P y n
The string "Python" has 6 characters, so its indexes run from 0 to 5. text[0] is P and text[1] is y; at the far end, text[5] is n. len(text) returns 6 here, the character count. Because the count of skips starts at 0, the last index of a non-empty string is len(text) - 1.
Counting from the end
text = "Python"
print(text[-1])
print(text[-2])
print(text[-6])n o P
A negative index counts from the right: text[-1] is the last character, text[-2] the one before it, and text[-6] reaches back to P. Python reads -k as len(text) - k, so in this 6-character string -1 means position 5 and -6 means position 0. Negative indexes pay off when lengths vary: the final character of an order ID is order_id[-1] whether the ID has 5 characters or 50.
| Character | Index from the left | Index from the right |
|---|---|---|
| 2 | 0 | -10 |
| 0 | 1 | -9 |
| 2 | 2 | -8 |
| 4 | 3 | -7 |
| - | 4 | -6 |
| 0 | 5 | -5 |
| 3 | 6 | -4 |
| - | 7 | -3 |
| 1 | 8 | -2 |
| 5 | 9 | -1 |
For the date "2024-03-15", the 2 indexes in every row differ by 10, the length of the string. So 9 and -1 both name the final 5, and 0 and -10 both name the first 2.
What does this program print?
stage = "pipeline"
print(stage[len(stage) - 3] + stage[-8])- lp
- IndexError
- ip
- in
Reading past the end raises IndexError
code = "SKU-42"
print(len(code))
print(code[5])
print(code[6])A 6-character string accepts indexes from -6 to 5. code[6] asks for a seventh character, so Python stops at line 4 with IndexError. Since len(code) sits 1 position past the last index, it is never a valid index; that off-by-one is how this error usually shows up, often from a loop whose range runs 1 step too far.
Each character is a string of length 1
account = "40817"
total = 0
for ch in account:
total += int(ch)
print(total)
print(account[0] + account[-1])
print(int(account[0]) + int(account[-1]))Output:
20 47 11
A single character in Python is a str of length 1, so indexing a digit hands back text. account[0] + account[-1] concatenates "4" and "7" into 47, and adding the digits as numbers takes int() on each, which gives 11. The loop at the top shows the other way to visit characters: for ch in account delivers each one in order, with no index needed.
Reading a character at a known position
Many record formats fix what each position means. A legacy export might pack 4 yes/no answers into one field such as "YNYY": index 0 says whether the account is active, 1 whether its email is verified, 2 whether it opted into marketing, and 3 whether it's a business account. One index reads one answer, and comparing that character with "Y" turns it into True or False.
flags = "YNYY"
print(flags[0] == "Y")
print(flags[1] == "Y")
print(flags[-1] == "Y")
date = "15/03/2024"
print(date[2] == "/" and date[5] == "/")
print("2024-03-15"[2] == "/")Output:
True False True True False
The last 2 lines are a format check. A DD/MM/YYYY date always has its slashes at positions 2 and 5, so testing those 2 characters accepts 15/03/2024 and rejects 2024-03-15 before a later step reads 20 as the day. The positions are part of the format's contract, and an index is how code holds a value to it.
About this lesson
This section is part of the Strings: Intermediate lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.