skip to content

Groups & Backreferences

Capturing groups numbered from one with group zero as the whole match, non-capturing groups for structure without capture, named groups, and backreferences. Interviewers ask you to extract fields from a line, which is exactly what groups are for.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

6

What is a capturing group in a Java regular expression, and how do you retrieve what it matched?

level: juniorimportance: must knowfreq 78%

answer

  1. () = capturing group, numbered by opening paren
  2. group(0) = whole match, group(1+) = captures
  3. must find()/matches() first or IllegalStateException
  4. non-participating group → group(n) returns null

basics

~20 s

A capturing group is the part of a pattern wrapped in parentheses (). After a successful match you read what it captured with matcher.group(n), where n is the group's number. group(0) is the whole match.

solid answer

~40 s

In Java regex, a capturing group is a sub-pattern wrapped in round parentheses, e.g. (\d{4}). When a Matcher finds a match, each group captures the text that part of the pattern matched. You retrieve them by number with matcher.group(n): group(0) is the entire match, group(1) the first group, group(2) the second, and so on, numbered left-to-right by their opening parenthesis. You must call find() or matches() first and check it returned true, otherwise group() throws IllegalStateException. If a group is optional and didn't participate in the match, group(n) returns null. Groups also let you apply quantifiers to a whole sub-pattern and form the basis of backreferences and replacement references like $1.

code

java · 8 lines
java
Pattern p = Pattern.compile("(\\d{4})-(\\d{2})");
Matcher m = p.matcher("2026-06");
if (m.matches()) {
    System.out.println(m.group());   // 2026-06  (group 0)
    System.out.println(m.group(1));  // 2026
    System.out.println(m.group(2));  // 06
    System.out.println(m.start(2));  // 5
}

go deeper

for a junior

Knows () makes a capturing group, group(0) is the whole match, group(1)+ are the captures, and you must match first.

for a middle

Adds start(n)/end(n) for positions, the null-vs-empty distinction, and IllegalStateException timing.

for a senior

Explains numbering by opening paren under nesting, when to use groups for quantifier scope vs capture, and the link to $1 replacement refs.

for a principal

Discusses capture overhead at scale, when to switch to non-capturing groups for clarity/perf, and API design implications of returning null.

## What a regular expression is A **regular expression** (regex) is a small pattern language for describing sets of strings. In Java you compile a pattern with `Pattern.compile("...")` and run it against input with a `Matcher` obtained via `pattern.matcher(input)`. The `Matcher` has `matches()` (must match the whole input), `find()` (finds the next match anywhere), and `lookingAt()` (matches at the start). ## What a group is A **group** is a part of the pattern enclosed in round parentheses `( ... )`. Groups do two things: 1. **They bundle** a sub-pattern so a quantifier (`*`, `+`, `?`, `{n}`) applies to the whole bundle. For example `(ab)+` matches `ababab`; without the parentheses `ab+` matches `abbb`. 2. **They capture** — they remember the exact substring that the sub-pattern matched, so you can read it back later. Such a group is a **capturing group**. ## Group numbering Groups are numbered **1, 2, 3...** by the left-to-right position of their **opening parenthesis** `(`. Nesting is allowed; the outer group simply has the smaller number because its `(` comes first. **Group 0** is special: it always refers to the *entire matched text*, even though you never wrote parentheses around the whole pattern. Example: in `(\d{4})-(\d{2})` matched against `2026-06`: - group 0 = `2026-06` (the whole match) - group 1 = `2026` - group 2 = `06` ## Retrieving captured text - `matcher.group()` or `matcher.group(0)` → the whole match. - `matcher.group(n)` → the text captured by group n. - `matcher.start(n)` / `matcher.end(n)` → the index in the input where group n began / ended (end is exclusive). **Order of operations matters.** You must first run `find()` or `matches()` (or `lookingAt()`) and confirm it returned `true`. Calling `group()` before a successful match throws `IllegalStateException` ("No match available"). ## Optional groups and null If a group is wrapped in an optional/alternation construct and did not take part in the match, `group(n)` returns **`null`** (not the empty string `""`). For example with pattern `(a)?b` matched against `b`, group(1) is `null`. The empty string is different — it means the group matched but matched zero characters. ## Why groups matter Capturing groups are the mechanism behind: extracting fields from text (dates, log lines), backreferences (`\1`) for matching repeated text, and replacement templates (`$1` in `replaceAll`). Understanding numbering is the foundation for all of these.

  • What does group(n) return if that group was optional and didn't match?
    null. That is distinct from an empty string, which means the group matched but consumed zero characters.
  • What happens if you call group() before find() or matches()?
    It throws IllegalStateException because no match has been performed yet.

Think of parentheses as labeled highlighter pens: each pair highlights a slice of the matched text so you can copy just that slice out afterwards. Group 0 is the highlight over the entire sentence.

saying these in an interview costs you the question

  • Saying group(1) is the whole match — that's group(0)
  • Forgetting to call find()/matches() before group()
  • Assuming a non-participating optional group returns "" instead of null
  • Confusing group count: numbering is by opening parenthesis, not by nesting depth

context

open as a page

How do named capturing groups work in Java regex, and how do you reference them?

level: middleimportance: should knowfreq 55%

basics

~10 s

Write (?<name>...) to give a capturing group a name. Read it back with matcher.group("name") instead of a number, and refer to it inside the pattern with \k<name>. Names make patterns readable.

open as a page

What is a non-capturing group (?:...) in Java regex, and why would you use one instead of a plain ()?

level: middleimportance: should knowfreq 62%

basics

~20 s

A non-capturing group (?:...) groups part of a pattern so a quantifier or alternation applies to it, but it does not capture or get a group number. Use it when you only need grouping, not the captured text.

open as a page

How do you extract multiple groups and their positions from text in Java, including across multiple matches?

level: middleimportance: should knowfreq 58%

basics

~10 s

Compile the pattern, get a Matcher, loop with while(m.find()), and for each match read m.group(n) and m.start(n)/m.end(n). find() advances to the next match each call; matches() only checks the whole input once.

open as a page

What is a backreference in a Java regex, and what is a common use for one?

level: seniorimportance: should knowfreq 52%

basics

~10 s

A backreference like \1 matches the same text that an earlier capturing group already matched (not the pattern again, the actual text). A common use is finding doubled words, e.g. \b(\w+)\s+\1\b matches 'the the'.

open as a page

How can capturing groups and backreferences contribute to catastrophic backtracking (ReDoS), and how do you design Java regexes to avoid it?

level: principalimportance: should knowfreq 34%

basics

~20 s

Java's regex engine backtracks. Ambiguous nested quantifiers and backreferences can make it try exponentially many combinations on certain inputs, freezing a thread (a denial of service). Avoid it with unambiguous patterns, atomic groups, possessive quantifiers, and input limits.

open as a page