4.2 String Indexing, Slicing, and Comparison

Key Takeaways

  • Positive indexing begins at 0 and increments to `len(s) - 1`, while negative indexing begins at `-1` (the last character) and decrements to `-len(s)`; indexing outside this range raises `IndexError`.
  • Slicing uses the syntax `s[start:stop:step]` and is boundary-tolerant, never raising an `IndexError` even when indices lie completely outside the string's length.
  • Negative slice steps reverse traversal direction, causing `start` to default to `len(s) - 1` and `stop` to default to the position before index 0, making `s[::-1]` the standard reversal idiom.
  • Sequence operators allow string concatenation (`+`), integer repetition (`*`), and substring membership verification (`in` and `not in`).
  • String comparison operators compare strings lexicographically code point by code point, which makes all ASCII uppercase letters evaluate as strictly less than lowercase letters (`'Z' < 'a'`).
Last updated: August 2026

String Indexing, Slicing, and Comparison

Strings in Python are ordered sequences of individual characters. Because they are sequences, they support all standard Python sequence operations, including direct indexing, advanced slicing, repetition, concatenation, and relational comparisons.


1. String Indexing Mechanics

Every character in a string occupies a fixed positional index. Python supports dual indexing:

  • Positive Indexing (Forward): Starts at 0 for the first character and advances to len(s) - 1 for the final character.
  • Negative Indexing (Backward): Starts at -1 for the rightmost character and decrements to -len(s) for the leftmost character.
String:         P     Y     T     H     O     N
Positive Index: 0     1     2     3     4     5
Negative Index: -6   -5    -4    -3    -2    -1
language = "PYTHON"

# Positive indexing
print(language[0])   # 'P'
print(language[5])   # 'N'

# Negative indexing
print(language[-1])  # 'N' (last character)
print(language[-6])  # 'P' (first character)

The IndexError Trap

Attempting to access an index outside the valid range [-len(s), len(s) - 1] immediately triggers an IndexError:

s = "PYTHON"  # len(s) is 6

# Out-of-bounds access raises IndexError
# s[6]   -> IndexError: string index out of range
# s[-7]  -> IndexError: string index out of range

Type Requirement: String indices must be integers. Passing floats (e.g., s[1.0]) or strings raises a TypeError: string indices must be integers.


2. Slicing Syntax and Parameter Defaults

Slicing creates a new substring from an existing string using the slice bracket syntax:

string[start:stop:step]\text{string}[\text{start} : \text{stop} : \text{step}]

  • start: The index where extraction begins (inclusive).
  • stop: The index where extraction terminates (exclusive; the character at stop is never included).
  • step: The stride or step interval between extracted characters (defaults to +1).

Default Values for Positive Step (step > 0)

When step is positive (or omitted):

  • start defaults to 0 (the beginning of the string).
  • stop defaults to len(s) (the end of the string).
  • step defaults to 1.
s = "PROGRAMMING"

print(s[0:4])    # 'PROG' (indices 0, 1, 2, 3)
print(s[:7])     # 'PROGRAM' (start defaults to 0)
print(s[7:])     # 'MING' (stop defaults to len(s))
print(s[:])      # 'PROGRAMMING' (full shallow copy)
print(s[::2])    # 'PGAMNG' (every 2nd character: indices 0, 2, 4, 6, 8, 10)

3. Boundary Tolerance in Slicing

A critical distinction on the PCAP exam is the difference in error handling between direct indexing and slicing:

  • Direct Indexing (s[i]): Strict boundary checking. Out-of-range indices raise IndexError.
  • Slicing (s[start:stop]): Completely boundary-tolerant. Python automatically clamps out-of-range boundaries to valid sequence limits without raising any errors.
s = "PYTHON"  # len(s) == 6

# Slices extending far beyond string boundaries
print(s[2:100])    # 'THON' (clamps stop to 6)
print(s[10:20])    # '' (empty string, start is past the end)
print(s[-100:2])   # 'PY' (clamps start to 0)
print(s[5:2])      # '' (empty string, stop <= start with positive step)

4. Negative Steps and String Reversal

When step < 0, the traversal direction is reversed (moving from right to left). This inverts the default slice boundaries:

  • start defaults to len(s) - 1 (the last character).
  • stop defaults to one position before index 0 (so index 0 is included).
Reversal Idiom: s[::-1]
Traverses from the last character back to the first character.
s = "PYTHON"

# Standard reversal idiom
print(s[::-1])       # 'NOHTYP'

# Slice with explicit negative indices and step
# Starts at index 4 ('O'), stops BEFORE index 1 ('Y')
print(s[4:1:-1])     # 'OHT' (indices 4, 3, 2)

# Direction conflict returning empty string
# Moving left-to-right with start < stop but negative step
print(s[1:4:-1])     # ''

Step Arithmetic Rule Table

ExpressionStart IndexStop IndexStepOutput on "PYTHON"
s[1:5:2]1 ('Y')5 ('N')+2'YH' (indices 1, 3)
s[5:0:-2]5 ('N')0 ('P')-2'NHY' (indices 5, 3, 1)
s[-2:-5:-1]-2 ('O')-5 ('Y')-1'OHT' (indices -2, -3, -4)
s[-4:]-4 ('T')6 (len)+1'THON' (indices -4, -3, -2, -1)

5. Sequence Operators: +, *, in, and not in

Strings support sequence concatenation, repetition, and membership testing:

Concatenation (+)

Combines two strings into a newly allocated string object. Both operands must be str:

greeting = "Hello" + " " + "World"
print(greeting)  # "Hello World"

# Mixed type error:
# "Score: " + 100  # TypeError: can only concatenate str (not "int") to str

Repetition (*)

Replicates a string by an integer multiplier. The multiplier can appear on either side (s * n or n * s):

print("-" * 5)      # "-----"
print(3 * "Abc")    # "AbcAbcAbc"
print("Python" * 0) # "" (multiplier <= 0 yields an empty string)
print("Python" * -3)# ""

Membership Testing (in and not in)

Tests whether a target substring exists as a contiguous slice within the string:

text = "Object Oriented Programming"

print("Oriented" in text)    # True
print("oriented" in text)    # False (case-sensitive)
print("OOP" in text)         # False (must be contiguous)
print("xyz" not in text)     # True

# The empty string rule:
# The empty string is considered a substring of EVERY string (including "")
print("" in text)            # True
print("" in "")              # True

6. Lexicographical Comparison Rules

Python compares strings using relational operators (<, <=, ==, !=, >=, >):

  • Comparisons are performed lexicographically (character-by-character from left to right).
  • Each character's ordinal position is determined strictly by its Unicode code point (ord()).
  • The comparison halts at the very first mismatched character.

The ASCII / Code Point Hierarchy

Because ASCII values dictate order: Digits (’0’-’9’: 48-57)<Uppercase (’A’-’Z’: 65-90)<Lowercase (’a’-’z’: 97-122)\text{Digits ('0'-'9': 48-57)} < \text{Uppercase ('A'-'Z': 65-90)} < \text{Lowercase ('a'-'z': 97-122)}

# 1. Case sensitivity: All uppercase letters precede all lowercase letters
print('Apple' < 'apple')   # True ('A' is 65, 'a' is 97)
print('Zebra' < 'ant')     # True ('Z' is 90, 'a' is 97)

# 2. Digit strings vs Alphabet strings
print('9' < 'A')           # True ('9' is 57, 'A' is 65)

# 3. Numeric string comparison pitfall
print('100' < '20')        # True ('1' is 49, '2' is 50; '1' < '2')
print(100 < 20)            # False (integer comparison compares numeric magnitude)

# 4. Prefix comparison rule (shorter prefix is smaller)
print('app' < 'apple')     # True (all matching, 'app' is shorter)

7. Built-in Functions: min() and max() on Strings

When applied to a string, min() and max() return the individual characters with the lowest and highest Unicode code points, respectively:

word = "Python"
print(min(word))   # 'P' (code point 80; 'h'=104, 'n'=110, 'o'=111, 't'=116, 'y'=121)
print(max(word))   # 'y' (code point 121)

phrase = "Hello World"
print(min(phrase)) # ' ' (space character has code point 32, which is lowest)

# Empty sequence error
# min("")  # ValueError: min() arg is an empty sequence
Loading diagram...
String Indexing and Slicing Boundary Intervals
Test Your Knowledge

What is the output of the following slice operation?

word = "OpenEDG"
print(word[10:20])

A
B
C
D
Test Your Knowledge

Which of the following comparison expressions evaluates to True in Python?

A
B
C
D
Test Your Knowledge

What is the result of evaluating the following Python expression?

s = "ABCDEF"
print(s[4:1:-1])

A
B
C
D
Test Your Knowledge

Given the string s = "Python 3.10", what is returned by min(s)?

A
B
C
D