ZetCode

Python Match.lastindex Attribute

last modified April 20, 2025

Introduction to Match.lastindex

The Match.lastindex attribute is part of Python's re module. It returns the index of the last matched capturing group in a regex.

This attribute is useful when working with complex patterns containing multiple groups. It helps identify which groups actually participated in the match.

Match.lastindex is None if no groups were matched. Otherwise, it's an integer representing the highest group number that matched.

Basic Syntax

The syntax for accessing Match.lastindex is straightforward:

match_object.lastindex

This attribute is read-only and automatically set during pattern matching. It's available on any match object returned by regex operations.

Basic Usage of Match.lastindex

Let's start with a simple example demonstrating basic usage.

basic_lastindex.py
#!/usr/bin/python

import re

text = "Date: 2023-12-25"
pattern = re.compile(r'(\d{4})-(\d{2})-(\d{2})')

match = pattern.search(text)
if match:
    print(f"Last matched group index: {match.lastindex}")
    print(f"Last matched group value: {match.group(match.lastindex)}")

This example shows how to access the last matched group index and its value. The pattern contains three capturing groups for date components.

pattern = re.compile(r'(\d{4})-(\d{2})-(\d{2})')

We compile a pattern with three capturing groups for year, month, and day. Each group matches a specific number of digits.

print(f"Last matched group index: {match.lastindex}")

This prints the index of the last matched group, which is 3 in this case. The index corresponds to the day component of the date.

Handling Optional Groups

Match.lastindex is particularly useful with optional groups.

optional_groups.py
#!/usr/bin/python

import re

texts = ["10:30", "10:30:45"]
pattern = re.compile(r'(\d{2}):(\d{2})(?::(\d{2}))?')

for text in texts:
    match = pattern.search(text)
    if match:
        print(f"Text: {text}")
        print(f"Lastindex: {match.lastindex}")
        print(f"Groups: {match.groups()}\n")

This demonstrates how lastindex changes with optional groups. The seconds group is optional in the time pattern.

Named Groups and lastindex

Match.lastindex works with both numbered and named groups.

named_groups.py
#!/usr/bin/python

import re

text = "John Doe, age 30"
pattern = re.compile(r'(?P\w+) (?P\w+), age (\d+)')

match = pattern.search(text)
if match:
    print(f"Lastindex: {match.lastindex}")
    print(f"Last group: {match.group(match.lastindex)}")
    print(f"All groups: {match.groups()}")

This shows that lastindex refers to group numbers even when using named groups. The age group is number 3 in this pattern.

Non-Participating Groups

Groups that didn't participate in the match affect lastindex.

non_participating.py
#!/usr/bin/python

import re

text = "color: red"
pattern = re.compile(r'color: (red|green|blue)(?:, (dark|light))?')

match = pattern.search(text)
if match:
    print(f"Lastindex: {match.lastindex}")
    print(f"Groups: {match.groups()}")

The second group is optional and doesn't participate in this match. lastindex is 1 because only the first group matched.

Nested Groups and lastindex

Nested group structures can make lastindex behavior interesting.

nested_groups.py
#!/usr/bin/python

import re

text = "12(34)"
pattern = re.compile(r'(\d+)(\((\d+)\))?')

match = pattern.search(text)
if match:
    print(f"Lastindex: {match.lastindex}")
    print(f"Groups: {match.groups()}")

This shows how nested groups affect the lastindex value. The inner group for digits becomes group 3 in the complete match.

Alternation and lastindex

Alternation patterns can produce different lastindex values.

alternation.py
#!/usr/bin/python

import re

texts = ["10 apples", "5 oranges"]
pattern = re.compile(r'(\d+) (apples|oranges|bananas)')

for text in texts:
    match = pattern.search(text)
    if match:
        print(f"Text: {text}")
        print(f"Lastindex: {match.lastindex}")
        print(f"Last group: {match.group(match.lastindex)}\n")

The alternation in the second group means lastindex will always be 2, but the matched text varies based on input.

Complex Pattern with Multiple Groups

Here's a more complex example with several groups.

complex_pattern.py
#!/usr/bin/python

import re

text = "Invoice #1001-2023, Total: $150.75"
pattern = re.compile(r'Invoice #(\d+)-(\d+), Total: \$(\d+)\.(\d{2})')

match = pattern.search(text)
if match:
    print(f"Lastindex: {match.lastindex}")
    for i in range(1, match.lastindex + 1):
        print(f"Group {i}: {match.group(i)}")

This demonstrates lastindex with multiple mandatory groups. We use it to iterate through all matched groups.

Best Practices

When using Match.lastindex, consider these best practices:

Performance Considerations

Accessing Match.lastindex is an O(1) operation with no significant performance impact. It's simply retrieving a stored value.

The attribute is most useful in scenarios where you need to know which groups participated in a match, particularly with complex optional groups.

Source

Python Match.lastindex documentation

This tutorial covered the essential aspects of Python's Match.lastindex attribute. Understanding this feature helps when working with complex regex patterns containing multiple groups.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.