Regex specific repeating interval parser, mostly working

Viewed 55

I have the following regex:

once|every (?:(?:([1-9][0-9]?[0-9]? )?(hours?|days?))|(?:(?:(?:(1st|2nd|3rd|4th|5th))? ?(monday|tuesday|wednesday|thursday|friday|saturday|sunday)?)|((?:[1-9]|[1-2][0-9]|3[0-1])(?:st|nd|rd|th))) ?(?:(of the month)? ?(?:(?:repeated every )([2-9][0-9]?[0-9]?) (weeks|months))?)?)

That works for most of what I need, but doesn't for the following string...

Every 20th of the month

The following work great...

Once
Every hour
Every day
Every 2 hours
Every 2 days
Every Monday
Every 1st of the month
Every 1st of the month repeated every 3 months
Every 2nd Monday of the month
Every 2nd Monday of the month repeated every 3 months

Can you help? Thanks

2 Answers

The problem is with the (?:(?:(1st|2nd|3rd|4th|5th))? ?(monday|tuesday|wednesday|thursday|friday|saturday|sunday)?) part: it may match an empty string. Hence, it always "wins".

You may fix it by removing ? quantifier after sunday) to make the day of week an obligatory pattern. See this regex demo.

Else, if the strings you check with the regex are standalone, you may enclose the whole pattern with ^(?: and )$ patterns to make them match entire pattern. See this regex demo.

Perhaps it is overkill, but I think if you replaced this part of your regex:

(1st|2nd|3rd|4th|5th)

By something like this:

(([1-9]?([2-90](((1st)|(2nd)|(3rd)|([4-90]th))|(1[0-9]th))))|((1st)|(2nd)|(3rd)|([4-9]th)))

    ...you might achieve the desired matching pattern. My idea here was covering any ordinal from 1st to 999th.

Please notice I haven't this regex tested, so perhaps it might need some corrections.


Also, consider what @Wictor answered: if you are searching these patterns over multiple strings instead of a single multi-string (in other words, all the strings you will check would be like the one in the example, as is, without any other char before and after), wrapping your regexp between ^ and $ will help making the regex more accurate.

And, as @Wictor said in his answer, if some subpattern accepts empty string as a match, it might behave unexpectedly. Exhaustive trial-and-error might help to find these kind of defficiencies, in order to correct them.

Related