/^/

Lesson 7 of 28

Groups

Using parentheses to treat a sequence of characters as a single unit you can quantify — plus a preview of capturing, non-capturing, and named groups.

5 min read

So far, quantifiers like *, +, and {n,m} have only ever applied to a single preceding character or class — a+ means “one or more a,” \d{3} means “three digits.” But what if you want to repeat a whole sequence of characters, like ab, as a unit? That’s what parentheses are for.

Grouping a sequence

Wrapping part of a pattern in (...) turns it into a single group that a quantifier can apply to as a whole, instead of just to the one character immediately before it.

/ab+/.test("ababab");   // true, but for the wrong reason — matches "a" then "bbb"-style runs of b
/(ab)+/.test("ababab"); // true — the whole "ab" unit repeats three times
/(ab)+/.test("abc");    // true — matches just the leading "ab"

Notice the difference between ab+ and (ab)+: without parentheses, + only attaches to the b, meaning “one a followed by one-or-more b.” With parentheses, + attaches to the entire ab sequence, meaning “one-or-more repetitions of ab.”

ab ababab abc
3 matches· capture groups: 1

The demo confirms it: (ab)+ matches ab (once), ababab (three repetitions), and just the ab prefix inside abc — each time treating ab as one repeatable chunk.

Grouping longer sequences

Groups aren’t limited to two characters — anything inside the parentheses, including character classes and other quantifiers, becomes part of the unit being repeated.

/(ha)+/.test("hahaha!");  // true — "ha" repeats three times before "!"
/(ha)+/.test("meh");      // false — no "ha" sequence at all
hahaha! ha meh
2 matches· capture groups: 1

Here (ha)+ finds two separate matches: hahaha (three repetitions in a row) and ha (a single repetition later in the text) — but nothing in meh, since it contains no ha sequence to repeat.

Groups can be quantified with anything

Just like single characters, a group can be followed by any quantifier you’ve learned: (ab)? (optional), (ab){2,4} (2 to 4 repetitions), or combined with alternation inside the parentheses, like (cat|dog)+, to mean “one or more repetitions of either ‘cat’ or ‘dog.’”

/^(cat|dog)+$/.test("catdogcat"); // true — three repetitions, mixing both words
/^(cat|dog)+$/.test("catbird");   // false — "bird" isn't one of the allowed repeats

Tip

Parentheses do more than grouping, though — by default, every (...) group also captures the exact text it matched, so your code can pull that piece out afterward (think of extracting just the area code from a phone number, or just the year from a date). We haven’t used that capturing behavior yet on purpose — it, along with non-capturing groups (?:...) and named groups (?<name>...), is exactly what the next lesson covers in depth.

Try it yourself

Using the second demo above, change the pattern from (ha)+ to (ha){2,} and predict which matches disappear.

What should happen

(ha){2,} requires at least two repetitions of ha in a row, so hahaha (three reps) still matches, but the standalone ha (only one rep) no longer does — it fails to reach the minimum of 2. This is the same “grouping + quantifier” mechanism as (ab)+, just with a more precise repetition count.

What’s next

You now know that parentheses group and repeat a sequence — but every group you’ve written has also been silently capturing its matched text. The next lesson digs into capturing groups, non-capturing groups, and named groups, and how to extract exactly the pieces of a match you actually want.

Quick check

What does the pattern (ab)+ match?

Besides letting you repeat a sequence, what's another major use of parentheses in regex, covered in the next lesson?