How to check if all date time specifier groups are present, in random order, with one regular expression

StackOverflow https://stackoverflow.com/questions/15679798

  •  30-03-2022
  •  | 
  •  

Question

I have the following string [datetime:yyyyMMddhhmmss] and I want to do some checks on it with regex. I know I can do it with multiple regex matches, but I wish (to learn) to do it in 1 expression, if possible. The string may also contain dashes/hyphens and underscores like so [datetime:yyyy_MM_dd_hh-mm-ss]. Spaces are removed with code up front. And the date time specifier groups (a group like yyyy) may be put somewhere in the format after [datetime: and before ]. So this would be a valid format as well: [datetime:dd_MM_yyyy_hh-mm-ss]

Checks to make:

  • I want to make sure [datetime:] is present. I can use pattern \[datetime:[\w\-]+\]
  • I want to make sure the 6 groups of yyyy MM dd hh mm ss are present, but they may come in random order.

I was trying to do it with positive lookaheads/lookbehinds like so \[datetime:[\w\-]+(?<=.?M{2}.?)\] to match the presense of MM somewhere in code. But this doesn't work.

Any regex guru that can help me out?

SOLUTION:

Based on Bergi's answer I now have this Regular expressions pattern: \[datetime:(?=.*?y{4})(?=.*?M{2})(?=.*?d{2})(?=.*?h{2})(?=.*?m{2})(?=.*?s{2})[\w\-]+\] that does the job. As it matches all of the given patterns below:

  • [datetime:yyyyMMddhhmmss]
  • [datetime:mmssyyyyddMMhh]
  • [datetime:mm_ss-yyyy_dd-MM-hh]
  • [datetime:mmssyyyyddMM_hours_hh]

Not that all of the above patterns do make sense, but this is exactly what I was looking for!

Was it helpful?

Solution

I was trying to do it with positive lookaheads/lookbehinds like so \[datetime:[\w\-]+(?<=.?M{2}.?)\] to match the presense of MM somewhere in code. But this doesn't work.

Lookbehinds are cumbersome to work with, as they are restricted on several levels in different engines (if supported at all). Also, your current code requires the MM to be contained in the last three chars of the datetime string, which seems not be what you want (an equivalent without lookbehind: \[datetime:[\w\-]*M{2}[\w\-]?\]).

Better use lookaheads:

\[datetime:(?=.*?y{4})(?=.*?M{2})(?=.*?d{2})…[\w\-]+\]

OTHER TIPS

\[datetime:[\w\-]+(?<=.?M{2}.?)\] to match the presense of MM somewhere in code. But this doesn't work.

The [\w\-]+ will match to the end of the input, so the lookahead will have nothing to match.

Why not try:

\[datetime:(?<=.*M{2})[\w\-]+\]

ie. the M{2} is anywhere after the : and before the ending ].

But in the end, your:

to do it in 1 expression, if possible

is likely to make this harder to maintain. Easier to use string operations to explicitly match the prefix [datetime: and suffix ] then use String.IndexOf on each of the elements in the remainder.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top