Regex tester · Guide
Regex Capture Group Guide: Numbered, Named and Non-Capturing Groups
Parentheses do two jobs in a regex: they group parts of a pattern, and they capture what matched so you can extract or reuse it. Keeping those two jobs separate is what makes complex patterns readable and fast.
Numbered groups
Every ( opens a capture group, numbered left to right by its opening parenthesis. Group 0 is always the entire match. In (\d{4})-(\d{2})-(\d{2}), group 1 is the year, 2 the month, 3 the day.
Nesting numbers by opening position, not by depth: in ((a)(b)), group 1 is ab, group 2 is a, group 3 is b:
(\d{4})-(\d{2})-(\d{2}) # 1 = year, 2 = month, 3 = day
(?<year>\d{4})-(?<month>\d{2}) # named: JS, Java, C#, PCRE, Go
(?P<year>\d{4})-(?P<month>\d{2}) # named: Python
(?:https?|ftp):// # grouped, not captured
(\w+)\s+\1 # backreference: a doubled wordNumbered groups are brittle. Adding a group in the middle of a pattern renumbers everything after it and silently breaks the code reading group 3.
Named groups
Naming solves the renumbering problem: (?<year>\d{4}) in JavaScript, Java, C#, PCRE and Go; (?P<year>\d{4}) in Python, where the P prefix marks its own dialect.
Access them by name — match.groups.year in JavaScript, m.group("year") in Python, m.Groups["year"].Value in C#. The pattern documents itself, and reordering it costs nothing.
Non-capturing groups
When you only need grouping — for alternation or to apply a quantifier — use (?:...). It groups without allocating a capture slot.
(?:https?|ftp):// groups the alternation without capturing the protocol. This keeps your group numbers meaningful and avoids collecting text you will never read.
A useful habit: make every group non-capturing by default, and only promote it to a capture when you actually extract the value.
Backreferences and lookarounds
A backreference matches the same text a group already captured: (\w+)\s+\1 finds a doubled word. In replacements the syntax differs — $1 in JavaScript, PHP and C#, \1 or \g<name> in Python.
Lookarounds group without consuming: (?=...) positive lookahead, (?!...) negative lookahead, (?<=...) and (?<!...) for lookbehind. Use them to assert context around a match rather than capturing it.
Extracting text between two markers is the most common capture task: START(.*?)END with a lazy quantifier, or better, a negated class such as START([^E]*)END when the delimiter allows it.
Frequently asked questions
Why is my group number wrong?
Groups are numbered by opening parenthesis, and adding one earlier in the pattern shifts every later number. Use named groups to avoid this entirely.
When should I use a non-capturing group?
Whenever you need parentheses for grouping but never read the captured text — alternation and quantifiers being the usual cases.
Do all languages support named groups?
Most modern ones do, but the syntax varies: (?<name>...) nearly everywhere, (?P<name>...) in Python. JavaScript has supported them since ES2018.
Ready to try it?
Open the free browser-based Regex tester and apply what you just read — no sign-up, runs locally.
Open the Regex tester tool