What is a capturing group in a Java regular expression, and how do you retrieve what it matched?
answer
- () = capturing group, numbered by opening paren
- group(0) = whole match, group(1+) = captures
- must find()/matches() first or IllegalStateException
- non-participating group → group(n) returns null
basics
~20 sA 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 sIn 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 linesPattern 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
Knows () makes a capturing group, group(0) is the whole match, group(1)+ are the captures, and you must match first.
Adds start(n)/end(n) for positions, the null-vs-empty distinction, and IllegalStateException timing.
Explains numbering by opening paren under nesting, when to use groups for quantifier scope vs capture, and the link to $1 replacement refs.
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