3

This might be a bit of a tricky one, I'm trying to come up with a regular expression to validate various given date intervals against the 8601 spec (https://en.wikipedia.org/wiki/ISO_8601#Durations). I have pretty much else all the cases working with the following regular expression:

^P(\d+(?:[,.]\d+)?Y)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?D)?(?:T(\d+(?:[,.]\d+)?H)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?S)?)?$

However the one place it falls down is in the aspect of the fractional unit only being allowed on the smallest supplied unit.

So for example:

P1DT1.5H is a valid string (The above regex technically allows this) P1.5DT1H is not a valid duration, as the hours are the smallest supplied unit. P1.5DT1.5H would also not be valid.

I've reached the end of my regex skills to try and figure out a way to incorporate this into the above. Anyone have any help or guidance on how this might be achived?

Kussie
  • 333
  • 1
  • 7
  • 1
    Can we assume the fractional part can only appear if there are no more digits to the right? Try `^P(?!.*\d\.\d.*\d)(?!$)(\d+(?:\.\d+)?Y)?(\d+(?:\.\d+)?M)?(\d+(?:\.\d+)?W)?(\d+(?:\.\d+)?D)?(T(?=\d)(\d+(?:\.\d+)?H)?(\d+(?:\.\d+)?M)?(\d+(?:\.\d+)?S)?)?$`. See https://regex101.com/r/pv3922/2 – Wiktor Stribiżew May 26 '22 at 07:05
  • That did the trick. I modified it a little so commas can also be used as the decimal symbol. But that's awesome thanks a lot. So the final version ended up looking like: `^P(?!.*\d[,.]\d.*\d)(?!$)(\d+(?:[,.]\d+)?Y)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?W)?(\d+(?:[,.]\d+)?D)?(T(?=\d)(\d+(?:[,.]\d+)?H)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?S)?)?$` – Kussie May 26 '22 at 09:17

1 Answers1

1

Assuming the fractional part can only appear if there are no more digits to the right, you can use

^P(?!.*\d[,.]\d.*\d)(?!$)(\d+(?:[,.]\d+)?Y)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?W)?(\d+(?:[,.]\d+)?D)?(T(?=\d)(\d+(?:[,.]\d+)?H)?(\d+(?:[,.]\d+)?M)?(\d+(?:[,.]\d+)?S)?)?$

See the regex demo.

The (?!.*\d[,.]\d.*\d) negative lookahead fails the match if there is a number with a fractional part followed with another number anywhere in the string.

You can learn more about the pattern used here in the Regex for ISO 8601 durations post.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563