Python: Non capturing group is not working in Regex

Viewed 203

I'm using non-capturing group in regex i.e., (?:.*) but it's not working.

I can still able to see it in the result. How to ignore it/not capture in the result?

Code:

import re

text = '12:37:25.790 08/05/20 Something   P  LR    0.156462 sccm   Pt   25.341343 psig something-else'

pattern = ['(?P<time>\d\d:\d\d:\d\d.\d\d\d)\s{1}',
           '(?P<date>\d\d/\d\d/\d\d)\s',
           '(?P<pr>(?:.*)Pt\s{3}\d*[.]?\d*\s[a-z]+)'
          ]

result = re.search(r''.join(pattern), text)

Output:

>>> result.group('pr')
            
'Something   P  LR    0.156462 sccm   Pt   25.341343 psig'

Expected output:

'Pt   25.341343 psig'

More info:

>>> result.groups()
            
('12:37:25.790', '08/05/20', 'Something   P  LR    0.156462 sccm   Pt   25.341343 psig')
3 Answers

Remove the non-capturing group from your named group. Using a non-capturing group means that no new group will be created in the match, not that that part of the string will be removed from any including group.

import re

text = 'Something   P  LR    0.156462 sccm   Pt   25.341343 psig something-else'

pattern = r'(?:.*)(?P<pr>Pt\s{3}\d*[.]?\d*\s[a-z]+)'

result = re.search(pattern, text)
print(result.group('pr'))

Output:

Pt   25.341343 psig

Note that the specific non-capturing group you used can be excluded completely, as it basically means that you want your regex to be preceded by anything, and that's what search will do anyway.

The quantifier is inside the named group, you have to place it outside and possibly make it non greedy to.

The updated pattern could look like:

(?P<time>\d\d:\d\d:\d\d.\d\d\d)\s{1}(?P<date>\d\d/\d\d/\d\d)\s.*?(?P<pr>Pt\s{3}\d*[.]?\d*\s[a-z]+)

Note that with he current pattern, the number is optional as all the quantifiers are optional. You can omit {1} as well.

If the number after Pt can not be empty, you can update the pattern using \d+(?:\.\d+)? matching at least a single digit:

(?P<time>\d\d:\d\d:\d\d.\d{3})\s(?P<date>\d\d/\d\d/\d\d)\s.*?(?P<pr>Pt\s{3}\d+(?:\.\d+)?\s[a-z]+)
  • (?P<time> Group time
  • \d\d:\d\d:\d\d.\d{3} Match a time like format
  • )\s Close group and match a whitespace char
  • (?P<date> Group date
    • \d\d/\d\d/\d\d Match a date like pattern
  • )\s Close group and match a whitespace char
  • .*? Match any char except a newline, as least as possible
  • (?P<pr> Group pr
    • Pt\s{3} Match Pt and 3 whitespace chars
    • \d+(?:\.\d+)? Match 1+ digits with an optional decimal part
  • \s[a-z]+ Match a whitespace char an 1+ times a char a-z
  • ) Close group

Regex demo

I think there is a confusion regarding the meaning of "non-capturing" here: It does not mean that the result omits this part, but that no match group is created in the result.

Example where the same regex is executed with a capturing, and a non-capturing group:

>>> import re
>>> match = re.search(r'(?P<grp>foo(.*))', 'foobar')
>>> match.groups()
('foobar', 'bar')
>>> match = re.search(r'(?P<grp>foo(?:.*))', 'foobar')
>>> match.groups()
('foobar',)

Note that match.group(0) is the same in both cases (group 0 contains the matching part of the string in full).

Related