Rexact
Cheatsheet

Regex durée ISO 8601 (P1DT12H)

Une durée ISO 8601 s'écrit « P3Y6M4DT12H30M5S » : « P », puis années, mois, jours (Y M D), puis « T » et heures, minutes, secondes (H M S), dans cet ordre, ou « P2W » pour des semaines. Il faut au moins un champ, et « T » doit être suivi d'au moins un champ. Les tentatives relues rendent tous les champs facultatifs : moment.js accepte « P », « PT » et même « PY » (nombre vide), iso8601-duration accepte « P » et « PT », isodate (Python) accepte « PT » ainsi que les semaines mélangées aux jours. Voici un motif construit sur la grammaire XML Schema, avec les semaines seules, comparé à ces tentatives.

/^P(?:(?:[0-9]+Y(?:[0-9]+M)?(?:[0-9]+D)?|[0-9]+M(?:[0-9]+D)?|[0-9]+D)(?:T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+(?:\.[0-9]+)?S))?|T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\.[0-9]+)?S)?|[0-9]+(?:\.[0-9]+)?S)|[0-9]+W)$/
passe 36/36 cas

Comparatif des patterns existants

SourcepatternScore sur le corpusReDoS
moment.js — tous les champs facultatifs et nombres vides : « P », « PT », « PY » passent ; signes et virgules partout (« P-1,5Y ») ; semaines mêlées aux jours^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$27 / 36sûr
iso8601-duration (npm) — non ancrée ; « P » et « PT » seuls passent, « xP1Dx » passe ; semaines mêlées aux joursP(?:(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(?:T(\d+(?:[\.,]\d+)?H)?(\d+(?:[\.,]\d+)?M)?(\d+(?:[\.,]\d+)?S)?)?)19 / 36indéterminé
isodate (Python) — « P » seul refusé mais « PT » passe ; décimales sur tous les champs, semaines mêlées aux jours, signe accepté^(?<sign>[+-])?P(?!\b)(?<years>[0-9]+([,.][0-9]+)?Y)?(?<months>[0-9]+([,.][0-9]+)?M)?(?<weeks>[0-9]+([,.][0-9]+)?W)?(?<days>[0-9]+([,.][0-9]+)?D)?((?<separator>T)(?<hours>[0-9]+([,.][0-9]+)?H)?(?<minutes>[0-9]+([,.][0-9]+)?M)?(?<seconds>[0-9]+([,.][0-9]+)?S)?)?$31 / 36indéterminé

Implémentation

const re = new RegExp("^P(?:(?:[0-9]+Y(?:[0-9]+M)?(?:[0-9]+D)?|[0-9]+M(?:[0-9]+D)?|[0-9]+D)(?:T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+(?:\\.[0-9]+)?S))?|T(?:[0-9]+H(?:[0-9]+M)?(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+M(?:[0-9]+(?:\\.[0-9]+)?S)?|[0-9]+(?:\\.[0-9]+)?S)|[0-9]+W)$", "");
re.test(input);

Limites

  • Valide seulement la FORME : aucun contrôle de plausibilité (« PT90M », « P99Y » sont acceptés) ni de cohérence calendaire ; une durée n'a pas de date de départ, « P1M » n'a donc pas de longueur fixe en jours.
  • Refusé volontairement : durée négative (« -P1D », absente d'ISO 8601-1:2004 mais admise par XML Schema), virgule décimale, décimale sur un champ autre que les secondes, semaines mêlées à d'autres champs (« P1W2D »), minuscules. Certaines bibliothèques (Java, moment.js) acceptent tout ou partie : ajustez le motif si vous les consommez.
  • ISO 8601 n'a pas été consultée (norme payante) : la grammaire retenue est celle de XML Schema 1.1 et de la RFC 3339, qui divergent sur « P1Y2D » (XML Schema l'accepte, la RFC ne l'écrit pas). La forme alternative « P0003-06-04T12:30:05 » n'est pas gérée.

Pages liées