How to uncapture string in regex?

Viewed 103

I would like to capture the date and time from the text below.

!----------------------------------------------
! 16/Oct/2020 10:11:14      12/Nov/2020 11:21:32
!----------------------------------------------
! 17/Oct/2020 10:11:14
!----------------------------------------------
! 18/Oct/2020 11:00:00      21/Oct/2020 12:00:00
!----------------------------------------------

My regex query:

(?P<StartDate>(?<=!\s)[^\s]+)\s+(?P<StartTime>[^\s]+)\s*(?P<EndDate>[^\s]+)\s+(?P<EndTime>[^\s]+)

However, for the second row it is capturing the exclamation mark and hyphen as well. How can I uncapture those things?

3 Answers

You should make your capture groups optional (at least the end time/date).

(?P<StartDate>(?<=!\s)[^\s]+)\s+(?P<StartTime>[^\s]+)\s*(?P<EndDate>[^!\s]+)?\s+(?P<EndTime>[^!\s]+)?

Here I make the EndDate and EndTime capture groups optional and also explicitely exclude exclamation marks (this is another avenue to explore, making the capture groups more specific to match only a date/time and not any non-whitespace characters).

For example, the dates can be matched with

[0-9]{2}\/[A-Za-z]{3}\/[0-9]{4}

and the times with

[0-9]{2}:[0-9]{2}:[0-9]{2}

Use the following regex. This is more specific than just the generic [^\s].

Side note, [^\s] can be replaced with \S.

You can make the end date and time optional by wrapping them in a non-capturing group (?:) and then adding a question mark after it to make that group optional: (?:)?

Regex
(?<=!\s)(?P<StartDate>[0-3]?[0-9]\/[A-Za-z]+\/\d+)\s+(?P<StartTime>[0-2]?[0-9]:[0-5]?[0-9]:[0-5]?[0-9])\s+(?:(?P<EndDate>[0-3]?[0-9]\/[A-Za-z]+\/\d+)\s+(?P<EndTime>[0-2]?[0-9]:[0-5]?[0-9]:[0-5]?[0-9]))?

Formatted

(?<=!\s)             # Look behind if starts with "! "
(?P<StartDate>   
    [0-3]?[0-9]
    \/
    [A-Za-z]+
    \/
    \d+
) 
\s+
(?P<StartTime>
    [0-2]?[0-9]
    :
    [0-5]?[0-9]
    :
    [0-5]?[0-9]
)
\s+
(?:                   # non capturing group
    (?P<EndDate>
       [0-3]?[0-9]
       \/
       [A-Za-z]+
       \/
       \d+
    )
    \s+
    (?P<EndTime>
        [0-2]?[0-9]
        :
        [0-5]?[0-9]
        :
        [0-5]?[0-9]
    )
)?                   # Make this group optional
Demo

https://regex101.com/r/Ky7g45/1

Cons

This will also match invalid dates from 32 - 39 and time hours from 24 - 29. If that matters, you'll need to add more regex with the | operator.

A pretty similar RegExp of yours
with a lookbehind (?<=) and an optional non-capturing group (?:)?:

(?<=!\s)(?P<StartDate>\S+)\s+(?P<StartTime>\S+)(?:\s+(?P<EndDate>\S+)\s+(?P<EndTime>\S+))?

Description and example at: Regex101.com

Related