By never_had_a_name

2010-08-18 13:17:47 8 Comments

How are non-capturing groups, i.e. (?:), used in regular expressions and what are they good for?


@Ricardo Nolde 2010-08-18 15:39:32

Let me try to explain this with an example.

Consider the following text:

Now, if I apply the regex below over it...


... I would get the following result:

Match ""
     Group 1: "http"
     Group 2: ""
     Group 3: "/"

Match ""
     Group 1: "https"
     Group 2: ""
     Group 3: "/questions/tagged/regex"

But I don't care about the protocol -- I just want the host and path of the URL. So, I change the regex to include the non-capturing group (?:).


Now, my result looks like this:

Match ""
     Group 1: ""
     Group 2: "/"

Match ""
     Group 1: ""
     Group 2: "/questions/tagged/regex"

See? The first group has not been captured. The parser uses it to match the text, but ignores it later, in the final result.


As requested, let me try to explain groups too.

Well, groups serve many purposes. They can help you to extract exact information from a bigger match (which can also be named), they let you rematch a previous matched group, and can be used for substitutions. Let's try some examples, shall we?

Ok, imagine you have some kind of XML or HTML (be aware that regex may not be the best tool for the job, but it is nice as an example). You want to parse the tags, so you could do something like this (I have added spaces to make it easier to understand):

   \<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
   \<(.+?)\> [^<]*? \</\1\>

The first regex has a named group (TAG), while the second one uses a common group. Both regexes do the same thing: they use the value from the first group (the name of the tag) to match the closing tag. The difference is that the first one uses the name to match the value, and the second one uses the group index (which starts at 1).

Let's try some substitutions now. Consider the following text:

Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.

Now, let's use this dumb regex over it:


This regex matches words with at least 3 characters, and uses groups to separate the first three letters. The result is this:

Match "Lorem"
     Group 1: "L"
     Group 2: "o"
     Group 3: "r"
     Group 4: "em"
Match "ipsum"
     Group 1: "i"
     Group 2: "p"
     Group 3: "s"
     Group 4: "um"

Match "consectetuer"
     Group 1: "c"
     Group 2: "o"
     Group 3: "n"
     Group 4: "sectetuer"

So, if we apply the substitution string:


... over it, we are trying to use the first group, add an underscore, use the third group, then the second group, add another underscore, and then the fourth group. The resulting string would be like the one below.

L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.

You can use named groups for substitutions too, using ${name}.

To play around with regexes, I recommend, which offers a good amount of details on how the regex works; it also offers a few regex engines to choose from.

@Steve Wortham 2010-08-19 15:43:39

@ajsie: Traditional (capturing) groups are most useful if you're performing a replacement operation on the results. Here's an example where I'm grabbing comma-separated last & first names and then reversing their order (thanks to named groups)...‌​0

@Vinoth Babu 2013-03-12 05:48:53

can i use it like this? ([?:]http|ftp)://([^/\r\n]+)(/[^\r\n]*)? Is it same as (?:http|ftp)://([^/\r\n]+)(/[^\r\n]*)? . please reply soon

@Ricardo Nolde 2013-04-19 13:45:22

No, it's not the same.

@Yevgeniy 2014-05-07 18:06:49

Might also point out that non-capturing groups are uniquely useful when using regex as split delimiters: "Alice and Bob"-split"\s+(?:and|or)\s+"

@Christian 2014-05-11 20:40:27

It would be interesting to have the difference between non-capturing groups (?:), and lookahead and lookbehind assertions (?=, ?!) explained. I just started learning about regular expressions, but from what I understand, non-capturing groups are used for matching and "return" what they match, but that "return value" is not "stored" for back-referencing. Lookahead and lookbehind assertions on the other hand are not only not "stored", they are also not part of a match, they just assert that something would match, but their "match" value is ignored, if I'm not mistaken... (Am I roughly right?)

@Barbs 2014-06-05 01:08:54

ok, got what the ?: does. Can someone explain what the ([^/\r\n]+) does? To me that's looking for a / then 1 or more line break at the beginning of the string but I fail to see how that helps match a url.

@Ricardo Nolde 2014-06-05 20:18:52

[] is a set; [123] matches any char inside the set once; [^123] matches anything NOT inside the set once; [^/\r\n]+ matches one or more chars that are different from /, \r, \n.

@carinlynchin 2017-05-04 01:16:23

thats what I understood too, but using this regexp /(?:\.com)(.+)$/ using this string I get: 0: ".com/testing/test.html" 1: "/testing/test.html" why am I getting the .com in the first one tho?

@Ricardo Nolde 2017-05-04 08:48:53

@Carine The 1st one is the whole match, not a group, which is correct. Remove the non-capturing group and you see an extra group show up.

@carinlynchin 2017-05-05 12:54:28

@RicardoNolde thank you . I thought maybe it was that but then I wasn't 100% sure it made sense to me. So thank you for the explanation

@Remario 2018-05-12 14:43:57

that regex needs to be escaped. (?:https?|ftp):\/\/([^\/\r\n]+)(\/[^\r\n]*)?

@rudyg123 2018-08-15 03:18:46

Very good explanation, thanks. Just a small callout. In the first result snippet in the answer, group 1 should be "https" not "http."

@Manu Chadha 2018-08-23 17:02:26

sorry, I am unable to understand how the \r and \n in your regex ([^/\r\n]+)(/[^\r\n]*) matching and /. ?

@Markus 2018-09-27 09:05:28

@ManuChadha: [^/\r\n]+ matches one or more characters that are not \r, \n and/or /. This means matches this expression. This is followed by /[^\r\n]* which matches any / that is followed by zero or more characters that are not \r and/or \n.

@Manu Chadha 2018-09-27 09:31:40

So the regex would match anything not just SO?

@Naved Ahmad 2019-01-07 08:02:12

Its extremely simple, We can understand with simple date example, suppose if the date is mentioned as 1st January 2019 or 2nd May 2019 or any other date and we simply want to convert it to dd/mm/yyyy format we would not need the month's name which is January or February for that matter, so in order to capture the numeric part, but not the (optional) suffix you can use a non-capturing group.

so the regular expression would be,


Its as simple as that.

@shekhar gehlot 2017-01-19 11:36:40

Let me try this with an example :-

Regex Code :- (?:animal)(?:=)(\w+)(,)\1\2

Search String :-

Line 1 - animal=cat,dog,cat,tiger,dog

Line 2 - animal=cat,cat,dog,dog,tiger

Line 3 - animal=dog,dog,cat,cat,tiger

(?:animal) --> Non-Captured Group 1

(?:=)--> Non-Captured Group 2

(\w+)--> Captured Group 1

(,)--> Captured Group 2

\1 --> result of captured group 1 i.e In Line 1 is cat,In Line 2 is cat,In Line 3 is dog.

\2 -->result of captured group 2 i.e comma(,)

So in this code by giving \1 and \2 we recall or repeat the result of captured group 1 and 2 respectively later in the code.

As per the order of code (?:animal) should be group 1 and (?:=) should be group 2 and continues..

but by giving the ?: we make the match-group non captured(which do not count off in matched group, so the grouping number starts from the first captured group and not the non captured), so that the repetition of the result of match-group (?:animal) can't be called later in code.

Hope this explains the use of non capturing group.

enter image description here

@6pack kid 2018-05-11 05:27:03

tl;dr non-capturing groups, as the name suggests are the parts of the regex that you do not want to be included in the match and ?: is a way to define a group as being non-capturing.

Let's say you have an email address [email protected]. The following regex will create two groups, the id part and part. (\p{Alpha}*[a-z])( For simplicity's sake, we are extracting the whole domain name including the @ character.

Now let's say, you only need the id part of the address. What you want to do is to grab the first group of the match result, surrounded by () in the regex and the way to do this is to use the non-capturing group syntax, i.e. ?:. So the regex (\p{Alpha}*[a-z])(? will return just the id part of the email.

@AmerllicA 2018-05-07 03:50:43

Open your Google Chrome devTools and then Console tab: and type this:


Run it and you will see:

["Pea", "P", "e", "a", index: 0, input: "Peace", groups: undefined]

The JavaScript RegExp engine capture three groups, the items with indexes 1,2,3. Now use non-capturing mark to see the result.


The result is:

["Pea", "e", "a", index: 0, input: "Peace", groups: undefined]

This is obvious what is non capturing group.

@Scott Anderson 2018-01-02 01:04:00

I cannot comment on the top answers to say this: I would like to add an explicit point which is only implied in the top answers:

The non-capturing group (?...) does not remove any characters from the original full match, it only reorganises the regex visually to the programmer.

To access a specific part of the regex without defined extraneous characters you would always need to use .group(<index>)

@Seshadri R 2018-07-12 07:04:25

You have provided the most important hint that was missing in the rest of the answers. I tried all the examples in them and using the choicest of expletives, as I did not get the desired result. Only your posting showed me where I went wrong.

@Scott Anderson 2018-07-12 12:04:57

Glad to hear it!

@RBT 2017-07-15 03:13:01

One interesting thing that I came across is the fact that you can have a capturing group inside a non-capturing group. Have a look at below regex for matching web urls:


Input url string:

var url = "";

The first group in my regex (?:([A-Za-z]+):) is a non-capturing group which matches the protocol scheme and colon : character i.e. http: but when I was running below code, I was seeing the 1st index of the returned array was containing the string http when I was thinking that http and colon : both will not get reported as they are inside a non-capturing group.


enter image description here

I thought if the first group (?:([A-Za-z]+):) is a non-capturing group then why it is returning http string in the output array.

So if you notice that there is a nested group ([A-Za-z]+) inside the non-capturing group. That nested group ([A-Za-z]+) is a capturing group (not having ?: at the beginning) in itself inside a non-capturing group (?:([A-Za-z]+):). That's why the text http still gets captured but the colon : character which is inside the non-capturing group but outside the capturing group doesn't get reported in the output array.

@Harini 2017-05-23 13:40:43

I think I would give you the answer, Don't use capture variables without checking that the match succeeded.


use warnings;
use strict;   
$_ = "bronto saurus burger";
if (/(?:bronto)? saurus (steak|burger)/)
    print "Fred wants a  $1";
    print "Fred dont wants a $1 $2";

In the above example, To avoid capturing bronto in $1, (?:) is used. If the pattern is matched , then $1 is captured as next grouped pattern. So, the output will be as below:

Fred wants a burger

It is Useful if you don't want the matches to be saved .

@Gaurav 2016-03-01 09:43:52

Well I am a JavaScript developer and will try to explain its significance pertaining to JavaScript.

Consider a scenario where you want to match cat is animal when you would like match cat and animal and both should have a is in between them.

 // this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]

 // using lookahead pattern it will match only "cat" we can
 // use lookahead but the problem is we can not give anything
 // at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]

 //so I gave another grouping parenthesis for animal
 // in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]

 // we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]

@user2369060 2016-02-04 08:07:28

HISTORICAL MOTIVATION: The existence of non-capturing groups can be explained with the use of parenthesis. Consider the expressions (a|b)c and a|bc, due to priority of concatenation over |, these expressions represent two different languages ({ac, bc} and {a, bc} respectively). However, the parenthesis are also used as a matching group (as explained by the other answers...).

When you want to have parenthesis but not capture the subexpression you use NON-CAPTURING GROUPS. In the example, (?:a|b)c

@J.M.I. MADISON 2018-08-04 23:59:40

I was wondering why. As I think the "why" is vital to memorizing this information.

@Jack Peng 2014-03-08 17:33:15

In complex regular expressions you may have the situation arise where you wish to use a large number of groups some of which are there for repetition matching and some of which are there to provide back references. By default the text matching each group is loaded into the backreference array. Where we have lots of groups and only need to be able to reference some of them from the backreference array we can override this default behaviour to tell the regular expression that certain groups are there only for repetition handling and do not need to be captured and stored in the backreference array.

@Bob Fincheimer 2010-08-18 13:22:48

Groups that capture you can use later on in the regex to match OR you can use them in the replacement part of the regex. Making a non-capturing group simply exempts that group from being used for either of these reasons.

Non-capturing groups are great if you are trying to capture many different things and there are some groups you don't want to capture.

Thats pretty much the reason they exist. While you are learning about groups, learn about Atomic Groups, they do a lot! There is also lookaround groups but they are a little more complex and not used so much.

Example of using later on in the regex (backreference):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [ Finds an xml tag (without ns support) ]

([A-Z][A-Z0-9]*) is a capturing group (in this case it is the tagname)

Later on in the regex is \1 which means it will only match the same text that was in the first group (the ([A-Z][A-Z0-9]*) group) (in this case it is matching the end tag).

@never_had_a_name 2010-08-18 13:27:02

could you give a simple example of how it will be used later to match OR?

@Bob Fincheimer 2010-08-18 13:33:57

i mean you can use to to match later or you can use it in the replacement. The or in that sentence was just to show you there are two uses for a capturing group

@Bill the Lizard 2010-08-18 13:24:36


Say you want to match numeric text, but some numbers could be written as 1st, 2nd, 3rd, 4th,... If you want to capture the numeric part, but not the (optional) suffix you can use a non-capturing group.



@NelsonGon 2019-07-13 06:07:47

Concise and probably the best explanation on here.

@RC. 2010-08-18 13:22:05


An example would be something to match an IP address:



@sepp2k 2010-08-18 13:23:33

It makes the group non-capturing, which means that the substring matched by that group will not be included in the list of captures. An example in ruby to illustrate the difference:

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]

@PRASANNA SARAF 2019-08-05 09:21:29

Why can't we just use "abc".match(/.(.)./).captures here ?

@sepp2k 2019-08-06 12:38:00

@PRASANNASARAF You can, of course. The point of the code was to show that (?:) does not produce a capture, not to demonstrate a useful example of (?:). (?:) is useful when you want to group a sub-expression (say when you want to apply quantifiers to a non-atomic sub-expression or if you want to restrict the scope of a |), but you don't want to capture anything.

Related Questions

Sponsored Content

8 Answered Questions

[SOLVED] How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops

  • 2014-03-20 19:09:13
  • Portland Runner
  • 823935 View
  • 552 Score
  • 8 Answer
  • Tags:   regex excel vba

19 Answered Questions

[SOLVED] How do you use a variable in a regular expression?

  • 2009-01-30 00:11:05
  • JC Grubbs
  • 686632 View
  • 1257 Score
  • 19 Answer
  • Tags:   javascript regex

73 Answered Questions

52 Answered Questions

[SOLVED] What is the best regular expression to check if a string is a valid URL?

29 Answered Questions

[SOLVED] Regular expression to match a line that doesn't contain a word

10 Answered Questions

[SOLVED] jQuery selector regular expressions

34 Answered Questions

[SOLVED] RegEx match open tags except XHTML self-contained tags

  • 2009-11-13 22:38:26
  • Jeff
  • 2708844 View
  • 1323 Score
  • 34 Answer
  • Tags:   html regex xhtml

18 Answered Questions

[SOLVED] How do you access the matched groups in a JavaScript regular expression?

  • 2009-01-11 07:21:20
  • nickf
  • 722113 View
  • 1279 Score
  • 18 Answer
  • Tags:   javascript regex

8 Answered Questions

[SOLVED] Is there a regular expression to detect a valid regular expression?

  • 2008-10-05 17:07:35
  • psytek
  • 199429 View
  • 970 Score
  • 8 Answer
  • Tags:   regex

17 Answered Questions

[SOLVED] Regular Expression for alphanumeric and underscores

  • 2008-12-03 04:25:27
  • Jim
  • 1033397 View
  • 548 Score
  • 17 Answer
  • Tags:   regex

Sponsored Content