RFC 2550 è una proposta satirica (pubblicata il 1 aprile 1999) per una rappresentazione ASCII efficiente nello spazio di timestamp in grado di supportare qualsiasi data (anche quelle precedenti all'inizio dell'universo e quelle oltre la fine prevista dell'universo). L'algoritmo per il calcolo di un timestamp conforme a RFC 2550 è il seguente (nota: tutti gli intervalli includono l'inizio ma escludono la fine - da 0 a 10.000 significa tutto n
dove 0 <= n < 10000
):
- Formato anno
- Anni da 0 a 10.000: un numero decimale di 4 cifre, imbottito a sinistra con zeri.
- Anni da 10.000 a 100.000: un numero decimale di 5 cifre, preceduto dal carattere A.
- Anni da 100.000 a 10 30 : il numero decimale per l'anno, preceduto dalla lettera ASCII maiuscola il cui indice nell'alfabeto inglese è uguale al numero di cifre nell'anno decimale, meno 5 (B per anni a 6 cifre, C per 7 -digit anni, ecc.).
- Anni da 10 30 a 10 56 : lo stesso formato da 10.000 a 10 30 , ricominciando le lettere con A e aggiungendo inoltre un prefisso (
^
) alla stringa (quindi l'anno 10 30 è rappresentato da^A1000000000000000000000000000000
, e l'anno 10 31 è rappresentato di^B10000000000000000000000000000000
). - Anni da 10 56 a 10 732 : l'anno è preceduto da due punti e due lettere maiuscole ASCII. Le lettere maiuscole formano un numero di base 26 che rappresenta il numero di cifre dell'anno, meno 57.
- Anni da 10 732 in poi: viene utilizzato lo stesso formato da 10 56 a 10 732 , estendendolo aggiungendo un punto di inserimento e una lettera maiuscola quando necessario.
- Anni AC (prima dell'anno 0): calcola la stringa dell'anno del valore assoluto dell'anno. Quindi, sostituisci tutte le lettere con il loro complemento di base 26 (A <-> Z, B <-> Y, ecc.), Sostituisci tutte le cifre con il loro complemento di base 10 (0 <-> 9, 1 <-> 8, ecc.) e sostituisci i simboli con punti esclamativi (
!
). Se la stringa dell'anno è di 4 cifre o meno (ovvero da -1 a -10.000), anteporre una barra (/
). Se la stringa dell'anno non è preceduta da una barra o da un punto esclamativo, anteporre un asterisco (*
).
- Mesi, giorni, ore, minuti e secondi : poiché questi valori sono al massimo solo 2 cifre, vengono semplicemente aggiunti a destra della stringa dell'anno, in ordine decrescente di significato, riempiti a sinistra con zero se necessario per formare Stringhe di 2 cifre.
- Precisione aggiuntiva : se è necessaria una precisione aggiuntiva (sotto forma di millisecondi, microsecondi, nanosecondi, ecc.), Tali valori vengono riempiti a sinistra con zeri a 3 cifre (poiché ogni valore è
1/1000
del valore precedente e quindi è al massimo999
) e aggiunto alla fine del timestamp, in ordine decrescente di significato.
Questo formato ha il vantaggio che l'ordinamento lessicale è equivalente all'ordinamento numerico del corrispondente timestamp - se il tempo A precede il tempo B, allora il timestamp per A verrà prima del timestamp per B quando verrà applicato l'ordinamento lessicale.
La sfida
Dato un elenco arbitrariamente lungo di valori numerici (corrispondenti a valori temporali in ordine decrescente di significato, ad es. [year, month, day, hour, minute, second, millisecond]
), Emette il corrispondente timestamp RFC 2550.
Regole
- Le soluzioni devono funzionare per qualsiasi dato input. Le uniche limitazioni dovrebbero essere il tempo e la memoria disponibile.
- L'input può essere preso in qualsiasi formato ragionevole e conveniente (come un elenco di numeri, un elenco di stringhe, una stringa delimitata da un singolo carattere non numerico, ecc.).
- L'input conterrà sempre almeno un valore (l'anno). I valori aggiuntivi sono sempre in ordine decrescente di significato (ad esempio, l'input non conterrà mai un valore del giorno senza un valore del mese o un secondo valore seguito da un valore del mese).
- L'immissione sarà sempre valida (ad es. Non ci saranno timestamp per il 30 febbraio).
- Sono vietati i builtin che calcolano i timestamp RFC 2550.
Esempi
Questi esempi usano input come una singola stringa, con i singoli valori separati da punti ( .
).
1000.12.31.13.45.16.8 -> 10001231134516008
12.1.5.1 -> 0012010501
45941 -> A45941
8675309.11.16 -> C86753091116
47883552573911529811831375872990.1.1.2.3.5.8.13 -> ^B478835525739115298118313758729900101020305008013
4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11 -> ^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711
-696443266.1.3.6.10.15.21.28 -> *V3035567330103061015021028
-5342 -> /4657
-4458159579886412234725624633605648497202 -> !Q5541840420113587765274375366394351502797
Implementazione di riferimento
#!/usr/bin/env python
import string
# thanks to Leaky Nun for help with this
def base26(n):
if n == 0:
return ''
digits = []
while n:
n -= 1
n, digit = divmod(n, 26)
digit += 1
if digit < 0:
n += 1
digit -= 26
digits.append(digit)
return ''.join(string.ascii_uppercase[x-1] for x in digits[::-1])
year, *vals = input().split('.')
res = ""
negative = False
if year[0] == '-':
negative = True
year = year[1:]
if len(year) < 5:
y = "{0:0>4}".format(year)
elif len(year) <= 30:
y = "{0}{1}".format(string.ascii_uppercase[len(year)-5], year)
else:
b26len = base26(len(year)-30)
y = "{0}{1}{2}".format('^'*len(b26len), b26len, year)
if negative:
y = y.translate(str.maketrans(string.ascii_uppercase+string.digits+'^', string.ascii_uppercase[::-1]+string.digits[::-1]+'!'))
if len(year) == 4:
y = '/' + y
if y[0] not in ['/', '!']:
y = '*' + y
res += y
for val in vals[:5]: #month, day, hour, minute, second
res += '{0:0>2}'.format(val)
for val in vals[5:]: #fractional seconds
res += '{0:0>3}'.format(val)
print(res)
-696443266.1.3.6.10.15.21.28
dovrebbe essere*V3035567339896938984978971
?