Numbered Groups in re Module

Regular Expressions Mar 20, 2026

Numbered Groups in re Module

Numbered groups are the default capturing groups created by plain parentheses (...) in regular expressions. Python’s re module automatically assigns them numbers starting from 1 (left to right). You can then reference them with match.group(1), \1 in substitutions, or as columns in pandas .str.extract(). Numbered groups are the simplest and most commonly used way to extract multiple structured fields from text in data science workflows.

TL;DR — Numbered Groups

  • (pattern) → creates group 1, 2, 3…
  • Access with match.group(1), \1, \2
  • Return multiple columns with pandas .str.extract()
  • Perfect for extracting IDs, dates, prices, emails in one pass

1. Basic Numbered Groups

import re

text = "Order ORD-98765 for $1,250.75 on 2026-03-19"

match = re.search(r"ORD-(\d+).*?\$(\d+(?:,\d+)?(?:\.\d+)?)", text)

print(match.group(0))   # full match: ORD-98765 for $1,250.75
print(match.group(1))   # order ID (group 1): 98765
print(match.group(2))   # amount (group 2): 1,250.75

2. Real-World Data Science Examples with Pandas

import pandas as pd

# Demo file so this example runs as-is (in your project this is your real log export)
pd.DataFrame({"log": [
    "2026-03-19 ERROR: Payment failed for ORD-12345 amount $1,250.75 Qty: 3 user alice@example.com!!! https://shop.example.com/o/12345 call +1 555-123-4567",
    "2026-03-19 WARNING: Slow response for ORD-98765 amount $87.50 Qty: 1 bob@company.com on 03/19/2026 aaaa",
    "INFO: user logged in ORD-555 amount $12.00 Qty: 2 carol@data.org <b>ok</b>",
]}).to_csv("logs.csv", index=False)

df = pd.read_csv("logs.csv")

# Extract the order ID and amount using numbered groups
df[["order_id", "amount"]] = df["log"].str.extract(
    r"ORD-(\d+).*?\$(\d+(?:,\d+)?(?:\.\d+)?)"
)

# A single group returns a DataFrame with column 0
df["email"] = df["log"].str.extract(r"(\S+@\S+\.[a-z]+)")[0]

print(df[["order_id", "amount", "email"]])

3. Numbered Groups in Substitution

# Reorder date using numbered groups
print(re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3/\2/\1", "2026-03-19"))   # 19/03/2026

# Swap first and last name
print(re.sub(r"(\w+)\s+(\w+)", r"\2, \1", "Alice Johnson"))          # Johnson, Alice

4. Best Practices in 2026

  • Use numbered groups when you need simple positional access to captured values
  • Switch to named groups (?P<name>...) for complex patterns with many groups
  • Use non-capturing groups (?:...) when you only need grouping
  • Pre-compile patterns that contain several numbered groups
  • Combine with pandas .str.extract() for vectorized multi-column extraction

How Python Numbers Groups

Python numbers capturing groups by counting opening parentheses from left to right. Group 0 is always the whole match, group 1 is the first opening parenthesis, and nested groups get numbers in the order their opening parentheses appear. Non-capturing groups and lookarounds are skipped.

Numbered groups are quick to write but fragile. If you insert a new group at the start of a pattern, every later number shifts by one. For short, stable patterns this is fine; for longer ones, named groups are easier to maintain.

The match object offers several ways to read groups: group(n) for one, groups() for all as a tuple, and span(n) for the start and end positions.

Worked Example: Nested Groups and Their Numbers

We match a date with a nested group for the year and month, and print every group with its number.

import re

m = re.search(r"((\d{4})-(\d{2}))-(\d{2})", "Invoice date: 2026-03-15")

for n in range(m.re.groups + 1):
    print(n, m.group(n), m.span(n))

Group 1 is the outer group 2026-03 because its opening parenthesis comes first, group 2 is the year, group 3 the month and group 4 the day. The spans show where each part sits in the original string, which helps when you need to highlight or slice the text.

Common Mistakes

  • Assuming groups are numbered by closing parentheses.
  • Forgetting that group 0 is the whole match.
  • Adding a group to an existing pattern without updating every number used later.
  • Calling group() on None when the pattern did not match; check the match first.

Quick Summary

  • Groups are numbered by opening parentheses.
  • Group 0 is the whole match.
  • Non-capturing groups get no number.
  • Use named groups when patterns grow.

Conclusion

Numbered groups are the foundation of structured text extraction in Python’s re module. In 2026 data science projects, they let you pull multiple fields (IDs, amounts, dates, emails…) in a single clean pattern and reference them instantly with group(1), \1, or pandas columns. Use numbered groups for simple cases, named groups for readability in complex patterns, and you’ll build faster, more maintainable text-processing pipelines than ever.

Next steps:

  • Take one of your current regex patterns and convert it to use numbered groups for multi-field extraction

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices