028. String Indexing
Zero-based indexing with negative wraparound
028. String Indexing
RAM Manager — Parsing Process Serial Numbers
Aryan’s RAM manager reads equipment serial numbers from a hardware inventory file. Each serial follows the format "XXXX-YYYYMMDD-N":
LAPT-20240315-7 → product code: LAPT, last digit: 7
SRVR-20231201-3 → product code: SRVR, last digit: 3He writes functions to extract the product code (first 4 chars), the last character (sequence number), and the first character (product family initial). His attempt has three off-by-one mistakes: serial[1:4] misses the first char, serial[1] returns the second char instead of the first, and serial[len(serial) - 2] returns the second-to-last character instead of the last.
The lesson: Python indexing is zero-based. The first element is
s[0], nots[1].s[len(s)-1]works buts[-1]is cleaner and less error-prone — negative indices count from the end and are always correct regardless of string length.
💡 Fun fact: Zero-based indexing dates back to the design of the C language in the early 1970s, where array indices represented pointer offsets from the start address. Python inherited zero-based indexing from C, but added negative indices as a purely Pythonic convenience — no equivalent exists in C arrays.
⚠️ Watch out: Off-by-one errors in indexing are the most common string bug — s[1:4] returns 3 characters (indices 1, 2, 3), not 4. When in doubt, count the characters by hand with the actual string and verify your slice boundaries before trusting the result.
🤔 Think about it: s[-1] is equivalent to s[len(s) - 1]. Both work, but -1 is shorter and will never accidentally go out of range. Can you think of a situation where s[len(s) - 1] would behave differently from s[-1] — or are they always identical for any non-empty string?
Learning objectives
- Access individual characters with positive indices (0-based)
- Use negative indices to count from the end
- Avoid off-by-one errors with string indexing
Key concepts
- string indexing
- zero-based indexing
- negative indices
Try it
Concept detail
Python strings are sequences indexed from 0. s[0] is first, s[1] is second, s[-1] is last. Valid positive indices: 0 to len(s)-1. Valid negative indices: -1 to -len(s). Going out of range raises IndexError: s[len(s)] is always wrong. Indices can be computed: s[len(s)//2] gets the middle character. Strings are immutable — you can read s[0] but not assign s[0] = ‘x’.
Solution
def get_product_code(serial):
return serial[0:4]
def get_last_char(serial):
return serial[-1]
def get_first_char(serial):
return serial[0]Tests
SERIAL = "LAPT-20240315-7"
def test_product_code():
assert get_product_code(SERIAL) == "LAPT"
def test_last_char():
assert get_last_char(SERIAL) == "7"
def test_first_char():
assert get_first_char(SERIAL) == "L"
def test_last_char_negative_index():
assert get_last_char("ABCDE") == "E"