AlgoDaily

Quantifiers and Alternation

Read at your own pace. Code execution, quizzes, progress tracking, and the AI tutor are available in the interactive view with JavaScript enabled.

From Alphabets To Amounts

Why this lesson matters

In Introduction to Regular Expressions, you learned how Python’s regex engine scans text and returns match objects. In Metacharacters and Character Classes, you expanded from literal text into flexible alphabets like \d, \w, and [A-Z].

Now we add two major controls:

  • Quantifiers: how many times something should appear
  • Alternation: which of several alternatives may appear

These make regex useful for real data cleaning: tokenizing logs, normalizing labels, detecting noisy IDs, and extracting patterns from machine learning datasets where text is rarely perfectly consistent.

From Alphabets To Amounts

Core Quantifiers

Repeating the previous pattern piece

A quantifier modifies the regex token immediately before it.

Common quantifiers:

Quantifier Meaning * 0 or more + 1 or more ? 0 or 1 {n} exactly n {m,n} from m to n {m,} at least m

Think of the previous token as a unit: \d+ means “one or more digits,” while [A-Z]? means “zero or one uppercase letter.”

```python
import re

text = "epoch 1 loss 0.94, epoch 12 loss 0.31, epoch 120 loss 0.08"

print("single digits:", re.findall(r"\d", text))
print("digit runs:", re.findall(r"\d+", text))
print("optional decimal parts:", re.findall(r"\d+\.\d+|\d+", text))
```

Greedy By Default

Quantifiers try to take as much as they can

Python regex quantifiers are greedy by default. That means *, +, and {m,n} will expand as far as possible while still allowing the whole pattern to match.

You can make many quantifiers lazy by adding ? after them:

  • .* = as much as possible
  • .*? = as little as possible

This matters when extracting text between delimiters, such as tags, brackets, or quoted fields in model metadata.

```python
import re

text = "<metric>accuracy</metric><metric>loss</metric>"

print("greedy:", re.findall(r"<metric>.*</metric>", text))
print("lazy:", re.findall(r"<metric>.*?</metric>", text))
```

Quantifier Check

Which pattern best matches a sequence containing one or more digits?

Ranges And Precision

Use bounded repetition when the shape is known

Open-ended quantifiers like + are flexible, but sometimes you know the exact width or a safe range.

Examples:

  • \d{4}: exactly four digits
  • [A-F0-9]{8}: eight uppercase hex characters
  • \w{3,12}: between three and twelve word characters

This is especially useful when validating IDs, experiment names, or version-like tokens before feeding them into downstream ML workflows.

```python
import re

runs = [
    "run_ab12 score=0.91",
    "run_A9F03C2B score=0.88",
    "run_123456789 score=0.77"
]

pattern = r"run_[A-F0-9]{8}"

for line in runs:
    print(line, "=>", re.findall(pattern, line))
```

Alternation Means Or

Choosing among alternatives

Alternation uses the pipe character: |.

It means “match the pattern on the left or the pattern on the right.”

Examples:

  • cat|dog matches cat or dog
  • accuracy|precision|recall matches one of those metric names
  • error|warning|info matches one of several log levels

A useful mental model: the regex engine reaches a fork in the road and tries one branch, then another if needed.

Alternation Means Or

Optional Letter

Complete the regex that matches both color and colour using one optional character:

colo__r

Fill in only the missing regex characters.

Fill in the blank: _____________

Alternation Truth

True or false: error|warning can match either the text error or the text warning.

Combining The Tools

Quantifiers and alternation become powerful together

Once you combine repetition with alternatives, compact patterns can cover many realistic variants.

Suppose your training logs are inconsistent:

  • error
  • errors
  • warning
  • warnings
  • numeric codes like 404 or 500

You can express those choices without writing a separate parser for each case.

```python
import re

logs = [
    "2 warnings, 0 errors",
    "warning: low memory",
    "error code 500",
    "all clear",
    "status 404 warning"
]

pattern = r"errors?|warnings?|\d{3}"

for line in logs:
    print(line, "=>", re.findall(pattern, line))
```

Design With Restraint

Practical regex habits

Quantifiers and alternation make patterns expressive, but they can also make patterns too permissive.

Good habits:

  • Prefer {m,n} when you know the valid length range.
  • Use + when at least one character must exist.
  • Use * carefully because it allows zero matches.
  • Put the most specific alternatives before broad ones when they might overlap.
  • Test against both examples that should match and examples that should not.

Next, we’ll tighten where matches are allowed to occur with Anchors and Boundaries.

Design With Restraint

Open interactive view →