Regex/Python - why is non capturing group captured in this case?
Question: Each element of this raw data array is parsed by regex

    
    
    ['\r\n\t\t\t\t\t\t', 
     'Monday, Tuesday, Wednesday, Thursday, Friday, Saturday:', 
     ' 12:00 pm to 03:30 pm & 07:00 pm to 12:00 am\t\t\t\t\t',      
     '\r\n\t\t\t\t\t\t', 
     'Sunday:', 
     ' 12:00 pm to 03:30 pm & 07:00 pm to 12:30 am\t\t\t\t\t']
    

This is my regex `(\\r|\\n|\\t)|(?:\D)(\:)`

<https://regex101.com/r/fV7wI2/1>

[![enter image description
here](http://i.stack.imgur.com/NJZXO.png)](http://i.stack.imgur.com/NJZXO.png)  

Please note that I'm trying to match the `:` after Saturday but not the `:` in
Time formats eg `12:00`

Although the above image classifies capturing/non capturing groups properly

on running `re.sub("(\\r|\\n|\\t)|(?:\D)(\:)",'',"Monday, Tuesday, Wednesday,
Thursday, Friday, Saturday:")`

returns

`'Monday, Tuesday, Wednesday, Thursday, Friday, Saturda'` (missing 'y' after
saturday)

instead of

`'Monday, Tuesday, Wednesday, Thursday, Friday, Saturday'`

why is this so?


Answer: You need to use a look-behind instead of a non-capturing group if you want to
check a substring for presence/absence, but exclude it from the match:

    
    
    import re
    s = "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday:"
    print(re.sub(r"[\r\n\t]|(?<!\d):",'',s))
    #                         ^^^^^^^ 
    # Result: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
    

See [IDEONE demo](https://ideone.com/UX5SNx)

Here, `(?<!\d)` only checks if the preceding character before a colon is not a
digit.

Also, alternation involves additional overhead, character class `[\r\n\t]` is
preferable, and you do not need any capturing groups (round brackets) since
you are not using them at all.

Also, please note that the regex is initialized with a raw string literal to
avoid overescaping.

Some [more details from Python _Regular Expression
Syntax_](https://docs.python.org/2/library/re.html#regular-expression-syntax)
regarding _non-capturing groups_ and _negative look-behinds_ :

> `(?<!...)`  
>  \- Matches if the current position in the string is not preceded by a match
> for `...`. This is called a **negative lookbehind assertion**. Similar to
> positive lookbehind assertions, the contained pattern must only match
> strings of some fixed length and shouldn’t contain group references.
> Patterns which start with negative lookbehind assertions may match at the
> beginning of the string being searched.
>
> `(?:...)`  
>  \- A non-capturing version of regular parentheses. Matches whatever regular
> expression is inside the parentheses, but the substring matched by the group
> cannot be retrieved after performing a match or referenced later in the
> pattern.

As look-behinds are _zero-width assertions_ (=expressions returning _true_ or
_false_ without moving the index any further in the string), they are exactly
what you need in this case where you want to _check_ but not _match_. A non-
capturing group will consume part of the string and thus will be part of the
match.

