使用分数验证 ISO 8601 持续时间字符串

Validating ISO 8601 Duration string with fractions

这可能有点棘手,我正在尝试提出一个正则表达式来根据 8601 规范 (https://en.wikipedia.org/wiki/ISO_8601#Durations) 验证各种给定的日期间隔。我几乎所有其他情况都使用以下正则表达式:

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

然而,它失败的一个地方是小数单位只允许在最小的提供单位上使用。

例如:

P1DT1.5H 是一个有效的字符串(上面的正则表达式在技术上允许这样做) P1.5DT1H 不是有效的持续时间,因为小时是提供的最小单位。 P1.5DT1.5H 也无效。

我的正则表达式技巧已经用完了,无法尝试找到一种方法将其合并到上面的内容中。有人对如何实现这一目标有任何帮助或指导吗?

假设小数部分只有在右边没有更多数字时才会出现,你可以使用

^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)?)?$

参见regex demo

如果字符串中的任意位置有一个数字的小数部分后跟另一个数字,(?!.*\d[,.]\d.*\d) 否定先行匹配将失败。

您可以在 post 中了解有关此处使用的模式的更多信息。