Repeated Characters in Regular Expressions

Regular Expressions Mar 20, 2026

Repeated Characters in Regular Expressions

Repeated characters are one of the most common patterns you need to match in real-world text. The Python re module provides powerful quantifiers that let you specify exactly how many times a character, group, or pattern can repeat. Mastering these is essential for cleaning logs, extracting sequences, removing duplicate punctuation, detecting spam patterns, and building robust feature-extraction pipelines in data science.

TL;DR — Quantifiers for Repeated Characters

  • * → zero or more
  • + → one or more
  • ? → zero or one
  • {n} → exactly n times
  • {n,} → n or more
  • {n,m} → between n and m times
  • ? after quantifier → non-greedy (minimal match)

1. Basic Quantifiers

import re

text = "aaaabbbccc! !! !!! 2026-03-19"

print(re.findall(r"a+", text))          # one or more
print(re.findall(r"b*", text))          # zero or more
print(re.findall(r"!{2,}", text))       # two or more exclamation marks
print(re.findall(r"\d{4}", text))       # exactly four digits

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")

# Example 1: Remove repeated punctuation
df["clean"] = df["log"].str.replace(r"!{2,}", "!", regex=True)

# Example 2: Extract sequences of repeated letters (e.g., "aaaa")
df["repeated_letters"] = df["log"].str.extract(r"([a-zA-Z])\1{2,}")

# Example 3: Match phone numbers with optional repeated digits
df["phone"] = df["log"].str.extract(r"(\d{3,4})")

3. Greedy vs Non-Greedy Matching

# Greedy (default)
print(re.search(r"a+", "aaaaaaa"))      # matches all

# Non-greedy
print(re.search(r"a+?", "aaaaaaa"))     # matches minimal

4. Best Practices in 2026

  • Use + for one-or-more and * for zero-or-more
  • Prefer {n,m} for exact control over repetition
  • Add ? after a quantifier for non-greedy matching
  • Always use raw strings r"..."
  • Combine with pandas .str.replace(regex=True) and .str.extract() for vectorized operations
  • Pre-compile patterns that are used repeatedly

Matching Repeats with Backreferences

Quantifiers repeat a pattern, but they do not require the repeated characters to be the same: [a-z]{3} matches "abc" as well as "aaa". To require the same character again, capture it and refer back to it with \1, as in (\w)\1.

This is useful for finding typos such as doubled letters, repeated words like "the the", or runs of the same digit in IDs.

Combining a backreference with a quantifier, such as (.)\1{2,}, finds a character repeated three or more times in a row.

Worked Example: Repeated Words and Long Runs

We detect doubled words and collapse long runs of the same character.

import re

text = "This is the the report, sooooo good!!!!"

print(re.findall(r"\b(\w+) \1\b", text))
print(re.sub(r"\b(\w+) \1\b", r"\1", text))
print(re.sub(r"(.)\1{2,}", r"\1", text))

The first pattern finds the doubled "the" and the second removes it. The last line collapses every character repeated three or more times, turning "sooooo" into "so" and the four exclamation marks into one.

Practical Tips

Before collapsing repeats, decide which repeats are valid. Doubled letters are normal in many English words, so collapsing runs of two would damage text, while runs of three or more are almost always noise or emphasis.

Count matches with len(re.findall(...)) before replacing, so you know how many values will change.

For IDs, a run of the same digit can be a real value, so flag such rows for review rather than changing them automatically.

Keep the original text in a separate column for comparison.

Common Mistakes

  • Expecting {3} to require identical characters.
  • Forgetting word boundaries around repeated words.
  • Collapsing doubles that are valid, such as "good".
  • Using a backreference before the group is defined.

Quick Summary

  • Quantifiers repeat patterns, not values.
  • \1 repeats the captured text.
  • (.)\1{2,} finds long runs.
  • Boundaries prevent partial words.

Conclusion

Repeated characters are handled elegantly with quantifiers in Python’s re module. In 2026 data science projects, mastering *, +, ?, {n,m} and greedy/non-greedy behavior lets you clean noisy text, extract patterns, and build reliable feature-engineering pipelines faster than ever. These techniques complete the core regex toolkit and prepare you for advanced text processing at scale.

Next steps:

  • Review your current text-cleaning code and replace manual loops with quantifier-based regex for repeated characters

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