COMPUTER PROGRAMMING 1 (PYTHON) • STRINGS & TEXT PROCESSING

String Indexing & Slicing — I can index and slice strings and explain how string indexing works at my level.

Learn to pinpoint and extract any character or substring from text using Python's powerful indexing and slicing syntax.

Historical Context & Motivation

Every piece of text you interact with on a computer—from a social-media username to a full webpage—is stored internally as a string, an ordered sequence of characters. Early programming languages forced developers to manage raw memory addresses just to read a single letter from a word. As languages evolved, they introduced cleaner ways to access individual characters and extract portions of text. Python, created by Guido van Rossum in 1991, drew inspiration from languages like C and ABC to offer one of the most intuitive systems for working with strings.

1972
C Language & Character Arrays
The C programming language introduced strings as arrays of characters, letting programmers access individual characters with bracket notation like str[0]. However, C required manual memory management, making text manipulation error-prone.
1987
ABC Language & Clean Syntax
The ABC language, a direct precursor to Python, introduced high-level string operations that hid memory details from the user. ABC's philosophy of readability and simplicity deeply influenced Python's design.
1991
Python 0.9 Released
Guido van Rossum released Python with built-in string indexing and slicing syntax. The slice notation using colons (s[start:stop]) became one of the language's signature features, making substring extraction readable and concise.
2008
Python 3 & Unicode Strings
Python 3 made all strings Unicode by default, meaning indexing works seamlessly with characters from every language—emoji included. The indexing and slicing syntax remained unchanged, proving its robust design.

The core question this lesson addresses is straightforward: given a string like "PYTHON", how do you pull out the third character, the last character, or a chunk of characters from the middle? Understanding string indexing and slicing is the foundation for virtually every text-processing task you will encounter in programming.

Core Principles & Definitions

Before you can slice and dice strings, you need to understand a handful of key ideas that Python builds upon. These principles apply not only to strings but also to lists, tuples, and other sequences in Python.

1

Zero-Based Indexing

Python counts positions starting at 0, not 1. The first character in a string is at index 0, the second is at index 1, and so on.
2

Negative Indexing

You can count backward from the end using negative numbers. Index -1 is the last character, -2 is second-to-last, and so on.
3

Immutability

Strings in Python are immutable—once created, individual characters cannot be changed. Indexing and slicing let you read characters, but you cannot assign to them directly.
4

Slicing Creates a New String

When you slice a string with s[a:b], Python returns a brand-new string containing the characters from index a up to (but not including) index b.
5

The Step Parameter

Slicing supports a third value: s[a:b:step]. The step controls how many positions to skip. A step of 2 grabs every other character; a step of −1 reverses the string.
✦ KEY TAKEAWAY
Think of a string like a row of lockers in a school hallway. Each locker has a number printed on its door—starting at locker 0. Indexing is opening one specific locker to see what's inside. Slicing is opening a range of lockers and collecting everything from locker 2 through locker 5. The locker numbers never change, and you can also walk backward from the last locker using negative numbers.

Visual Explanation — How Indexing Maps to Characters

The diagram below shows how Python maps both positive and negative index numbers to each character in the string "PYTHON". Notice that the positive indices run left to right starting at 0, while the negative indices run right to left starting at −1.

Each box represents one character. The top row shows positive indices (0–5) and the bottom row shows negative indices (−6 to −1). Both refer to the same character in the string.

A crucial detail to remember is that the last valid positive index is always len(s) − 1. For a 6-character string, that means index 5. If you try to access s[6], Python will raise an IndexError because no character exists at that position. Negative indexing, on the other hand, starts at −1 for the last character and goes down to −len(s) for the first character.

How Slicing Works — The Syntax Explained

Slicing extends indexing by letting you grab a range of characters at once. The general form uses up to three parameters separated by colons inside brackets.

SLICE SYNTAX
s[start : stop : step]
start = the index where the slice begins (included). stop = the index where the slice ends (excluded). step = how many positions to advance between characters (default is 1).
NUMBER OF CHARACTERS IN A SLICE
count = ⌈(stop − start) ÷ step⌉
When all three values are positive, the number of characters returned equals the ceiling of (stop − start) divided by step. This is why s[1:5] returns exactly 5 − 1 = 4 characters when step is 1.

The most important rule to internalize is that the stop index is always excluded. Think of slicing positions as sitting on the fence posts between characters, not on the characters themselves. If s = "PYTHON", then s[1:4] starts at index 1 ('Y') and collects characters up to but not including index 4, yielding "YTH".

💡 Default Values
You can omit any of the three parameters. If you omit start, Python defaults to the beginning (0). If you omit stop, it defaults to the end of the string. If you omit step, it defaults to 1. For example, s[:3] gives "PYT" and s[3:] gives "HON".
REVERSE A STRING
s[::-1]
A step of −1 with no start or stop reverses the entire string. For "PYTHON", this returns "NOHTYP".

Detailed Breakdown — Common Slice Patterns

The table below catalogs the most commonly used indexing and slicing patterns. All examples use s = "PYTHON" (length 6). Study the pattern column carefully—you'll reuse these forms constantly.

Common string indexing and slicing patterns
ExpressionResultExplanation
s[0]'P'First character (positive index)
s[-1]'N'Last character (negative index)
s[1:4]'YTH'Characters from index 1 up to (not including) 4
s[:3]'PYT'First three characters (start defaults to 0)
s[3:]'HON'From index 3 to the end (stop defaults to length)
s[:]'PYTHON'Full copy of the string
s[::2]'PTO'Every other character (step = 2)
s[::-1]'NOHTYP'Reversed string (step = −1)
s[-3:]'HON'Last three characters using negative start
The top half highlights which characters are selected by s[1:4]. The bottom shows the "fence-post" model: slice boundaries sit between characters, so index 1 starts before 'Y' and index 4 ends before 'O'.

The fence-post model at the bottom of the diagram is one of the most helpful mental images for understanding slicing. Each fence post has a number, and the characters sit between adjacent posts. When you write s[1:4], you are selecting everything between fence post 1 and fence post 4—three characters in total.

Worked Example — Extracting a Username from an Email

Suppose you have an email address stored as a string and you need to extract the username (the part before the @ symbol). Let's walk through this step by step.

Extract the Username from an Email Address
1
Step 1 — Define the StringStart with the email address stored in a variable: email = "student42@school.edu". The string has 21 characters total, and we need to find where the @ symbol sits.
2
Step 2 — Find the Position of '@'Use the built-in .find() method to locate the index of '@': at_pos = email.find("@"). This returns 9 because '@' sits at index 9 (counting from 0).
at_pos = 9
3
Step 3 — Slice from Start to the '@'Now slice the string from the beginning up to (but not including) the '@' position: username = email[:at_pos]. Since we omit the start value, Python begins at index 0. The stop value is 9, so we get characters at indices 0 through 8.
username = "student42"
4
Step 4 — Verify with Negative IndexingAs a sanity check, you could also grab the last three characters to confirm the domain extension: ext = email[-3:]. Starting at index −3 and going to the end gives us "edu", which matches the domain.
ext = "edu"
5
Step 5 — Put It All TogetherThe complete mini-program: email = "student42@school.edu" → at_pos = email.find("@") → username = email[:at_pos] → print(username). This prints "student42". Slicing combined with string methods makes text extraction clean and readable.
Output: student42

Common Mistakes & Best Practices

String indexing and slicing are intuitive once you get the hang of them, but beginners frequently stumble on a few predictable pitfalls. The table below compares common mistakes with the correct approach.

Common indexing/slicing mistakes and fixes
MistakeWhat HappensCorrect Approach
Using s[1] expecting the first characterReturns the second character because indexing starts at 0.Use s[0] to get the first character.
Accessing s[len(s)]Raises IndexError. The last valid index is len(s) − 1.Use s[-1] or s[len(s) - 1].
Expecting s[2:5] to include index 5Only includes indices 2, 3, and 4. The stop value is always excluded.Remember: stop is exclusive. Use s[2:6] if you need through index 5.
Trying s[0] = "X"Raises TypeError because strings are immutable.Build a new string: s = "X" + s[1:].
Out-of-range slice like s[2:100]No error! Python silently clips the stop value to the string length and returns what it can.This is actually safe—slicing never raises an IndexError. But be aware it may return fewer characters than expected.
✦ KEY TAKEAWAY
Here's a helpful asymmetry to remember: indexing out of range causes an error, but slicing out of range does not. Think of indexing like ordering a specific seat number at a concert—if that seat doesn't exist, you get turned away. Slicing is like asking for "seats 5 through 200"—the venue just gives you however many seats are available starting from 5, no complaints.

Connection to Advanced String Operations

String indexing and slicing are your entry point into a much larger world of text processing. As you advance, you'll encounter methods and techniques that build directly on the indexing concepts you've learned here. The table below connects what you know now to what's coming next.

From indexing basics to advanced text processing
What You Know NowWhat's Coming Next
s[i] to access one characterLooping through every character with for char in s: — iteration
s[a:b] to extract substringsString methods like .split(), .replace(), and .join() for complex text manipulation
s[::-1] to reverse a stringPalindrome checking algorithms and other string-based coding challenges
Strings as sequences of charactersLists use the same indexing and slicing syntax: my_list[1:4] works identically
Manual text extraction with slicingRegular expressions (re module) for pattern-based text extraction at scale

The beauty of Python's design is consistency. Once you master s[start:stop:step] for strings, you can apply the exact same syntax to lists, tuples, and even NumPy arrays later in your programming journey. This single concept will serve you from intro CS through data science and beyond.

Practice Problems

Test your understanding with these five problems. Each one builds on the concepts covered in this lesson. Try to solve each problem mentally or on paper before reading the answer.

PROBLEM 1 — CONCEPTUAL
Explain why Python uses zero-based indexing. If you have a string s = "HELLO", why is the first character at index 0 instead of index 1? What practical benefit does this provide for slicing?
PROBLEM 2 — BASIC CALCULATION
Given word = "BASKETBALL", what does each of the following expressions return? (a) word[3] (b) word[-2] (c) word[0:6]
PROBLEM 3 — INTERMEDIATE
Given msg = "Hello, World!", write a slice expression that extracts just the word "World" (without the exclamation mark). Then write a second expression using negative indexing to extract the same word.
PROBLEM 4 — APPLIED
A date is stored as date = "2025-01-15" in YYYY-MM-DD format. Using only slicing (no .split()), extract the year, month, and day into three separate variables. Then construct the date in MM/DD/YYYY format by concatenating your slices with '/' characters.
PROBLEM 5 — CRITICAL THINKING
A student claims that s[::2] + s[1::2] will always produce the same characters as the original string s, just possibly in a different order. Is this claim correct? Explain your reasoning, and test it mentally with s = "ABCDE". Bonus: under what condition would the result equal the original string?

Lesson Summary

Python strings are ordered sequences of characters, and every character has a position number called an index. Positions count from 0 (zero-based indexing) on the left and from −1 (negative indexing) on the right. You access a single character with s[i] and extract a substring with slicing using the syntax s[start:stop:step], where the stop value is always exclusive.

Key points to remember: strings are immutable (you cannot change individual characters in place), slicing out of range is safe (Python clips silently), and a step of −1 reverses the string. Mastering this syntax gives you a powerful tool for text processing—and the same bracket notation transfers directly to lists, tuples, and other Python sequences.

Varsity Tutors • Computer Programming 1 (Python) • String Indexing & Slicing