Battez les expressions régulières pures aux dates de validation ISO 8601


12

Dans ValiDate ISO 8601 de RX , le défi était de n'utiliser que des expressions régulières standard pour valider les formats et valeurs de date standard (le premier est un travail courant pour RX, le second était inhabituel). La réponse gagnante a utilisé 778 octets. Ce défi est de le battre en utilisant n'importe quelle langue de votre choix, mais sans fonctions ou classes de date spéciales .

Défi

Trouvez le code le plus court

  1. valide toutes les dates possibles du calendrier grégorien proleptique (qui s'applique également à toutes les dates avant sa première adoption en 1582),
  2. ne correspond à aucune date invalide et
  3. n'utilise pas de fonctions, méthodes, classes, modules ou similaires prédéfinis pour gérer les dates (et les heures), c'est-à-dire s'appuie sur des opérations de chaîne et numériques.

Production

La sortie est véridique ou falsey. Il n'est pas nécessaire de sortir ou de convertir la date.

Contribution

L'entrée est une chaîne unique dans l'un des 3 formats de date ISO 8601 étendus - pas d'heure.

Les deux premiers sont ±YYYY-MM-DD(année, mois, jour) et ±YYYY-DDD(année, jour). Les deux ont besoin d'un boîtier spécial pour le jour bissextile. Ils sont naïvement appariés séparément par ces RX étendus:

(?<year>[+-]?\d{4,})-(?<month>\d\d)-(?<day>\d\d)
(?<year>[+-]?\d{4,})-(?<doy>\d{3})

Le troisième format d'entrée est ±YYYY-wWW-D(année, semaine, jour). C'est le plus compliqué en raison du schéma complexe des semaines bissextiles.

(?<year>[+-]?\d{4,})-W(?<week>\d\d)-(?<dow>\d)

Conditions

Une année bissextile dans le calendrier grégorien proleptique contient le jour bissextile …-02-29 et est donc de 366 jours, …-366existe donc . Cela se produit dans n'importe quelle année dont le nombre ordinal (éventuellement négatif) est divisible par 4, mais pas par 100 à moins qu'il ne soit également divisible par 400. L' année zéro existe dans ce calendrier et c'est une année bissextile.

Une longue année dans le calendrier hebdomadaire ISO contient une 53e semaine …-W53-…, que l'on pourrait qualifier de « semaine bissextile ». Cela se produit toutes les années où le 1er janvier est un jeudi et en outre toutes les années bissextiles où c'est un mercredi. 0001-01-01et 2001-01-01sont les lundis. Il se produit généralement tous les 5 ou 6 ans, de façon apparemment irrégulière.

Une année comporte au moins 4 chiffres. Les années de plus de 10 chiffres ne doivent pas être prises en charge, car elles sont suffisamment proches de l'âge de l'univers (environ 14 milliards d'années). Le signe plus en tête est facultatif, bien que la norme actuelle suggère qu'il devrait être requis pendant des années avec plus de 4 chiffres.

Les dates partielles ou tronquées, c'est-à-dire avec une précision inférieure au jour, ne doivent pas être acceptées. Des tirets séparés -sont requis dans tous les cas. (Ces conditions préalables permettent +de toujours être facultatif.)

Règles

C'est du code-golf. Le code le plus court en octets gagne. Une réponse antérieure gagne une égalité.

Cas de test

Tests valides

2015-08-10
2015-10-08
12015-08-10
-2015-08-10
+2015-08-10
0015-08-10
1582-10-10
2015-02-28
2016-02-29
2000-02-29
0000-02-29
-2000-02-29
-2016-02-29
+2016-02-29
200000-02-29
-200000-02-29
+200000-02-29
2016-366
2000-366
0000-366
-2000-366
-2016-366
+2016-366
2015-081
2015-W33-1
2015-W53-7
+2015-W53-7
+2015-W33-1
-2015-W33-1
 2015-08-10 

Le dernier est éventuellement valide, c'est-à-dire que les espaces de début et de fin dans les chaînes d'entrée peuvent être coupés.

Formats invalides

-0000-08-10     # that's an arbitrary decision
15-08-10        # year is at least 4 digits long
2015-8-10       # month (and day) is exactly two digits long, i.e. leading zero is required
015-08-10       # year is at least 4 digits long
20150810        # though a valid ISO format, we require separators; could also be interpreted as a 8-digit year
2015 08 10      # separator must be hyphen-minus
2015.08.10      # separator must be hyphen-minus
2015–08–10      # separator must be hyphen-minus
2015-0810
201508-10       # could be October in the year 201508
2015 - 08 - 10  # no internal spaces allowed
2015-w33-1      # letter ‘W’ must be uppercase
2015W33-1       # it would be unambiguous to omit the separator in front of a letter, but not in the standard
2015W331        # though a valid ISO format we require separators
2015-W331
2015-W33        # a valid ISO date, but we require day-precision
2015W33         # though a valid ISO format we require separators and day-precision
2015-08         # a valid ISO format, but we require day-precision
201508          # a valid but ambiguous ISO format
2015            # a valid ISO format, but we require day-precision

Dates invalides

2015-00-10  # month range is 1–12
2015-13-10  # month range is 1–12
2015-08-00  # day range is 1–28 through 31
2015-08-32  # max. day range is 1–31
2015-04-31  # day range for April is 1–30
2015-02-30  # day range for February is 1–28 or 29
2015-02-29  # day range for common February is 1–28
2100-02-29  # most century years are non-leap
-2100-02-29 # most century years are non-leap
2015-000    # day range is 1–365 or 366
2015-366    # day range is 1–365 in common years
2016-367    # day range is 1–366 in leap years
2100-366    # most century years are non-leap
-2100-366   # most century years are non-leap
2015-W00-1  # week range is 1–52 or 53
2015-W54-1  # week range is 1–53 in long years
2016-W53-1  # week range is 1–52 in short years
2015-W33-0  # day range is 1–7
2015-W33-8  # day range is 1–7

2
hors sujet, mais peut-être utile - Stack Overflow: stackoverflow.com/questions/28020805/… (si je ne devais pas poster ça, dites-le moi)
Daniele D

Et si le programmeur est un YEC (Young-Earth Creationist)?
Leaky Nun

À propos de -0000-08-10ce qu'est exactement la décision arbitraire? Ne permettant pas l'année comme négatif 0?
edc65

@ edc65 Oui, +0000-08-10et 0000-08-10devrait être utilisé à la place. Notez, cependant, que la réponse acceptée dans la variante d'expression régulière de ce défi échoue à ce cas de test particulier, donc ce n'est pas vraiment une condition d'échec (c'est-à-dire un doit , pas un must ).
Crissov

@KennyLau Alors le programmeur a tort .
Arcturus

Réponses:


2

JavaScript (ES6), 236

236 octets permettant 0 an négatif ( -0000). Renvoie vrai ou faux

s=>!!([,y,w,d]=s.match(/^([+-]?\d{4,})(-W?\d\d)?(-\d{1,3})$/)||[],n=y%100==0&y%400!=0|y%4!=0,l=((l=y-1)+8-~(l/4)+~(l/100)-~(l/400))%7,l=l==5|l==4&!n,+d&&(-w?d>`0${2+n}0101001010`[~w]-32:w?(w=w.slice(2),w>0&w<(53+l)&d>-8):d[3]&&d>n-367))

L'ajout de la vérification pour 0 négatif coupe 2 octets mais en ajoute 13. Notez qu'en javascript, la valeur numérique -0existe et qu'elle est spéciale pour être égale à 0, mais elle l' 1/-0est -Infinity. Cette versione renvoie 0 ou 1

s=>([,y,w,d]=s.match(/^([+-]?\d{4,})(-W?\d\d)?(-\d{1,3})$/)||[],n=y%100==0&y%400!=0|y%4!=0,l=((l=y-1)+8-~(l/4)+~(l/100)-~(l/400))%7,l=l==5|l==4&!n,+d&&(-w?d>`0${2+n}0101001010`[~w]-32:w?(w=w.slice(2),w>0&w<(53+l)&d>-8):d[3]&&d>n-367))&!(!+y&1/y<0)

Tester

Check=
  s=>!! // to obtain a true/false 
  (
    // parse year in y, middle part in w, day in d
    // day will be negative with 1 or 3 numeric digits and could be 0
    // week will be '-W' + 2 digits
    // month will be negative with2 digits and could be 0
    // if the date is in format yyyy-ddd, then w is empty
    [,y,w,d] = s.match(/^([+-]?\d{4,})(-W?\d\d)?(-\d{1,3})$/) || [],
    n = y%100==0 & y%400!=0 | y%4!=0, // n: not leap year
    l = ((l=y-1) + 8 -~(l/4) +~(l/100) -~(l/400)) % 7, 
    l = l==5| l==4 & !n, // l: long year (see http://mathforum.org/library/drmath/view/55837.html)
    +d && ( // if d is not empty and not 0
     -w // if w is numeric and not 0, then it's the month (negative)
     ? d > `0${2+n}0101001010`[~w] - 32 // check month length (for leap year too)
      : w // if w is not empty, then it's the week ('-Wnn')
        ? ( w = w.slice(2), w > 0 & w < (53+l) & d >- 8) // check long year too
        : d[3] && d > n-367 // else d is the prog day, has to be 3 digits and < 367 o 366
    )
  )

console.log=x=>O.textContent += x +'\n'

OK=['1900-01-01','2015-08-10','2015-10-08','12015-08-10','-2015-08-10','+2015-08-10'
,'0015-08-10','1582-10-10','2015-02-28','2016-02-29','2000-02-29'
,'0000-02-29','-2000-02-29','-2016-02-29','+2016-02-29','200000-02-29'
,'-200000-02-29','+200000-02-29','2016-366','2000-366','0000-366'
,'-2000-366','-2016-366','+2016-366','2015-081','2015-W33-1'
,'2015-W53-7','+2015-W53-7','+2015-W33-1','-2015-W33-1','2015-08-10']

KO=['-0000-08-10','15-08-10','2015-8-10','015-08-10','20150810','2015 08 10'
,'2015.08.10','2015–08–10','2015-0810','201508-10','2015 - 08 - 10','2015-w33-1'
,'2015W33-1','2015W331','2015-W331','2015-W33','2015W33','2015-08','201508'
,'2015','2015-00-10','2015-13-10','2015-08-00','2015-08-32','2015-04-31'
,'2015-02-30','2015-02-29','2100-02-29','-2100-02-29','2015-000'
,'2015-366','2016-367','2100-366','-2100-366','2015-W00-1'
,'2015-W54-1','2016-W53-1','2015-W33-0','2015-W33-8']

console.log('Valid')
OK.forEach(x=>console.log(Check(x)+' '+x))
console.log('Not valid')
KO.forEach(x=>console.log(Check(x)+' '+x))
<pre id=O></pre>

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.