Oblicz znacznik czasu RFC 2550

26

RFC 2550 jest satyryczną propozycją (opublikowaną 1 kwietnia 1999 r.) Dotyczącą energooszczędnej reprezentacji ASCII znaczników czasu, które mogą obsługiwać dowolną datę (nawet te przed początkiem wszechświata i te, które minęły przewidywany koniec wszechświata). Algorytm obliczania znacznika czasu zgodnego z RFC 2550 jest następujący (uwaga: wszystkie zakresy obejmują początek, ale wykluczają koniec - od 0 do 10 000 oznacza wszystko ngdzie 0 <= n < 10000):

  • Format roku
    • Lata od 0 do 10 000: 4-cyfrowa liczba dziesiętna, uzupełniona lewymi zerami.
    • Lata od 10 000 do 100 000: 5-cyfrowa liczba dziesiętna, poprzedzona znakiem A.
    • Lata od 100 000 do 10 30 : liczba dziesiętna dla roku, poprzedzona wielką literą ASCII, której indeks w alfabecie angielskim jest równy liczbie cyfr w roku dziesiętnym, minus 5 (B dla 6 cyfr, C dla 7 - lata cyfrowe itp.).
    • Lata 10 30 do 10 56 : ten sam format co 10 000 do 10 30 , rozpoczynając litery od A i dodatkowo poprzedzając znak daszka ( ^) ciągiem (więc rok 10 30 jest reprezentowany przez ^A1000000000000000000000000000000, a rok 10 31 jest reprezentowany przez ^B10000000000000000000000000000000).
    • Lata 10 56 do 10 732 : rok jest poprzedzony dwoma CARETS i dwa ASCII wielkimi literami. Wielkie litery tworzą liczbę podstawową 26 reprezentującą liczbę cyfr w roku, minus 57.
    • Lata 10 732 i następne: stosuje się ten sam format dla 10 56 do 10 732 , rozszerzając go, dodając w razie potrzeby dodatkowy znak karetki i wielką literę.
    • Lata pne (przed rokiem 0): obliczenie ciągu roku bezwzględnej wartości roku. Następnie zamień wszystkie litery na ich uzupełnienie podstawy-26 (A <-> Z, B <-> Y itd.), Zamień wszystkie cyfry na uzupełnienie podstawy-10 (0 <-> 9, 1 <-> 8, itp.) i zamień karetki wykrzyknikami ( !). Jeśli ciąg roku ma 4 cyfry lub mniej (tj. Od -1 do -10 000), wstaw ukośnik ( /). Jeśli ciąg roku nie jest poprzedzony ukośnikiem lub wykrzyknikiem, wstaw gwiazdkę ( *).
  • Miesiące, dni, godziny, minuty i sekundy : ponieważ te wartości są najwyżej 2 cyframi, są one po prostu dodawane po prawej stronie ciągu roku, w kolejności malejącej znaczenia, w razie potrzeby uzupełniane lewymi zerami 2-cyfrowe ciągi znaków.
  • Dodatkowa precyzja : jeśli potrzebna jest dodatkowa precyzja (w postaci milisekund, mikrosekund, nanosekund itp.), Wartości te są dopełniane od zera do 3 cyfr (ponieważ każda wartość ma 1/1000poprzednią wartość, a zatem najwyżej 999) i dołączane na końcu znacznika czasu, w malejącym porządku ważności.

Ten format ma tę zaletę, że sortowanie leksykalne jest równoważne sortowaniu numerycznemu odpowiedniego znacznika czasu - jeśli czas A nastąpi przed czasem B, to znacznik czasu A pojawi się przed znacznikiem czasu B, gdy zastosowane zostanie sortowanie leksykalne.

Wyzwanie

Biorąc pod uwagę dowolnie długą listę wartości liczbowych (odpowiadających wartościom czasu w malejącym porządku istotności, np. [year, month, day, hour, minute, second, millisecond]), Wypisz odpowiedni znacznik czasu RFC 2550.

Zasady

  • Rozwiązania muszą działać dla każdego danego wkładu. Jedynymi ograniczeniami powinien być czas i dostępna pamięć.
  • Dane wejściowe mogą być podejmowane w dowolnym rozsądnym, wygodnym formacie (takim jak lista cyfr, lista ciągów, ciąg ograniczony pojedynczym znakiem innym niż cyfra itp.).
  • Dane wejściowe zawsze będą zawierać co najmniej jedną wartość (rok). Dodatkowe wartości są zawsze w malejącym porządku ważności (np. Dane wejściowe nigdy nie będą zawierać wartości dziennej bez wartości miesiąca lub drugiej wartości, po której następuje wartość miesiąca).
  • Dane wejściowe zawsze będą ważne (np. 30 lutego nie będzie żadnych znaczników czasu).
  • Wbudowane obliczenia znaczników czasu RFC 2550 są zabronione.

Przykłady

W tych przykładach zastosowano dane wejściowe jako pojedynczy ciąg znaków, a poszczególne wartości oddzielono kropkami ( .).

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

Realizacja referencyjna

#!/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)
Mego
źródło
Z pewnością -696443266.1.3.6.10.15.21.28powinno być *V3035567339896938984978971?
Neil
11
@ Nee Dopóki nie wymyślimy negatywnych miesięcy. Grudzień
Mego
1
@TaylorScott Dodatkowa precyzja : jeśli potrzebna jest dodatkowa precyzja (w postaci milisekund, mikrosekund, nanosekund itp.), Wartości te są uzupełnione od zera do 3 cyfr.
Mego
2
Wydaje mi się, że specyfikacja podana w pytaniu tak naprawdę nie pasuje do RFC2550. Jak rozumiem, po przejściu przez trzy karetki liczba liter powinna wzrosnąć szybciej niż karetka, ponieważ pochodzi ona z serii Fibonacciego (4 karetki oznacza 5 liter, 5 karetek oznacza 8 liter itp.) Czy można bezpiecznie zakładamy, że powinniśmy ignorować ten aspekt RFC?
James Holderness
1
@JamesHolderness Masz rację, pomieszałem specyfikację. Jest jednak za późno, aby to poprawić, ponieważ istnieją już odpowiedzi, które zostałyby unieważnione.
Mego

Odpowiedzi:

5

JavaScript (ES6), 325 bajtów

f=
s=>s.split`.`.map((n,i)=>i?`00${n}`.slice(i>5?-3:-2):n<'0'?g(n.slice(1),'!','*','/').replace(/\w/g,c=>c>'9'?(45-parseInt(c,36)).toString(36):9-c):g(n),g=(n,c='^',d='',e='',l=n.length)=>l<5?e+`000${n}`.slice(-4):l<31?d+(l+5).toString(36)+n:h(l-30,c)+n,h=(n,c)=>n?c+h(--n/26|0,c)+(n%26+10).toString(36):'').join``.toUpperCase()
;
<input oninput=o.value=f(this.value);><input id=o>

Szokująco długo.

Neil
źródło
Czy miałbyś coś przeciwko dodaniu fragmentu stosu do łatwego testowania?
Mego
@Mego Gotowe. Naprawiono także literówki, które wkradały się (przypadkowo usunąłem część kodu podczas kopiowania i wklejania, ponieważ zawiodłem się w nim zawijaniem wierszy. Ups.)
Neil
3

Befunge, 418 384 bajtów

Trudno z góry powiedzieć, jak duży może być program Befunge, a kiedy zacząłem nad tym pracować, pomyślałem, że może mieć szansę na konkurowanie. Okazuje się, że się myliłem.

~:59*-!:00p:2*1\-10p:9*68*+20p>0>#~$_v
68*-:0\`30p\>>:"P"%\"P"/9+p30g#v_1+:~>
0\`v`\0:\p04<<:+1g04-$<_\49+2*v>0>+#1:#\4#g\#0`#2_130p040p5-::01-`\49+2*-:
v:$_\50p\$:130g:1+30p:!^!:-1\*<>g*"A"++\49+2*/50g1-:
_$1+7g00g40g!**:!>_40g:!v!:\g8<^00*55*g01%*2+94:p05
|#9/"P"\%"P":<:_,#!>#:<$_1-00g^v3$\_\#`\0:>#g+
>10g*20g+,1+:^v\&\0+2`4:_@#`<0+<
/*v*86%+55:p00<_$$>:#,_$1+~0^
^!>+\55+/00g1-:^

Wypróbuj online!

James Holderness
źródło
3

Perl 5 , 328 322 317 301 + 1 ( -a) = 302 bajtów

$_=shift@F;if(($l=y/-//c)<5){s/^/0 x(4-$l)/e}elsif($l<57){s/^/'^'x($l>30).chr 65+($l-5)%26/e}else{$l-=57;do{s/\^*\K/'^'.chr 65+$l%26/e}while$l=int$l/26;s/^\^\K\D-?\d/^A$&/}if(s/-//){s%^....$%/$&%;eval join'',reverse'!/',0..9,A..Z,"y/A-Z0-9^/";s%^[^!/]%*$&%}printf$_.'%02d'x(@F>5?5:@F).'%03d'x(@F-5),@F

Wypróbuj online!

Nie golfił

$_=shift@F; # Store the year in the default variable for easier regex

if(($l=y/-//c)<5){      # if the length of the year is less than 5
    s/^/0 x(4-$l)/e         # pad with leading zeros to 4 digits
}elsif($l<57){          # if the length is less than 57
    s/^/'^'x($l>30).chr 65+($l-5)%26/e  # put a carat at the front if there are more than 30 characters
                        # and map the length minus 5 to A-Z
}else{
    $l-=57;         # offset the length by 57
    do{         
        s/\^*\K/'^'.chr 65+$l%26/e # put a carat at the front and map the length to base 26 (A-Z)
    }while$l=int$l/26;  # until the length is down to 0
    s/^\^\K\D-?\d/^A$&/ # insert an extra '^A' to pad the result to at least 2 characters if there was only 1
}
if(s/-//){          # if the year is negative
    s%^....$%/$&%;          # put a '/' in front of a 4 digit year
    eval join'',reverse'!/',0..9,A..Z,"y/A-Z0-9^/"; # map A-Z,0-9, and ^ to Z-A,9-0, and ! respectively
    s%^[^!/]%*$&%           # add a * at the front if there are no other indicators
}
printf$_.           # output the year
'%02d'x(@F>5?5:@F).             # followed by the month, day, hour, and minutes, padded to 2 digits
'%03d'x(@F-5),@F                # followed by fractional seconds, padded to three digits
Xcali
źródło
3

Java 8, 653 640 637 623 bajtów

s->{String r="",q="ABCDEFGHIJKLMNOP",z=q+"QRSTUVWXYZ",y="0123456789",x;int i=0,f=0,t,u;for(String p:s){if(p.charAt(0)<46){p=p.substring(1);f=1;}t=p.length();if(i++<1){r+=(t<5?"000".substring(t-1):t<32?(char)(t+60):t<58?"^"+(char)(t+34):"");if(t>57){for(r+="^^",u=675;u<t-57;u*=26)r+="^";x="";for(String c:Long.toString(t-57,26).toUpperCase().split(""))x+=z.charAt((y+q).indexOf(c));r+=x;}r+=p;if(f>0){x=t<5?"/":t<32?"*":r.replace("^","!").replaceAll("[^!]","");for(char c:r.toCharArray())x+=c>93?"":"ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210".charAt((z+y).indexOf(c));r=x;}}else r+=i>6?t<2?"00"+p:t<3?0+p:p:t<2?0+p:p;}return r;}

Wpisz jako String-array i return-type as String.

Okazało się, że jest dość długi (zgodnie z oczekiwaniami), ale zdecydowanie można go jeszcze zagrać w golfa. Cieszę się, że to działa po dłuższej zabawie…

Wypróbuj tutaj.

Wyjaśnienie:

  • for(String p:s){: Pętla nad częściami
    • if(p.charAt(0)<46){p=p.substring(1);f=1;}: Określ, czy jest ujemny, a jeśli tak, usuń znak minus i ustaw flagę, aby zmniejszyć liczbę bajtów
    • t=p.length();: Uzyskaj liczbę cyfr
    • if(i++<1){: Jeśli jest to pierwsza liczba (rok):
      • t<5?"000".substring(t-1): Jeśli jest to 0-100 000 (wyłącznie): w razie potrzeby dodaj wiodące zera
      • t<32?(char)(t+60): Jeśli jest 100 000–10 30 (wyłącznie): dodaj literę wiodącą
      • t<58?"^"+(char)(t+34): Jeśli jest to 10 30 -10 732 (wyłącznie): Dodaj dosłowny "^"+ wiodącą nas
      • if(t>57)for(r+="^^",u=675;u<t-57;u*=26)r+="^";: Dodaj odpowiednią ilość literału "^"+ x="";for(String c:Long.toString(t-57,26).toUpperCase().split(""))x+=z.charAt((y+q).indexOf(c));r+=x;: wiodące litery (konwersja od 26 do alfabetu)
      • r+=p;: Dodaj sam rok do ciągu wynikowego
      • if(f>0){: Jeśli rok był ujemny:
        • x=t<5?"/":t<32?"*":r.replace("^","!").replaceAll("[^!]","");: Utwórz ciąg tymczasowy xz poprawnym /, *jednym lub wieloma!
        • for(char c c:r.toCharArray())x+=c>93?"":"ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210".charAt((z+y).indexOf(c));: Wykonaj konwersję (A*Z, B*Y, 0 SAR 9, 1 SAR 8 itd.)
        • r=x;: A następnie ustaw wynik na ten temp String x
    • else: Jeśli jest to miesiąc, dni, godziny, minuty, sekundy, milisekundy, mikrosekundy, nanosekundy lub mniejsze:
      • i>6?t<2?"00"+p:t<3?0+p:p: Jeśli jest to milisekunda lub mniejsza: W razie potrzeby dodaj wiodące zera
      • :t<2?0+p:p;: W przeciwnym razie (miesiąc, dni, godziny, minuty, sekundy): W razie potrzeby dodaj pojedyncze wiodące zero
  • return r: Zwraca wynik
Kevin Cruijssen
źródło
Input may be taken in any reasonable, convenient format (such as a list of numerics, a list of strings, a string delimited by a single non-digit character, etc.).- możesz wziąć dane wejściowe jako listę liczbową i pominąć kosztowne dzielenie i konwersję.
Mego
1
@Mego Niestety domyślne wartości liczbowe ( long64 największe są największe) są zbyt małe w Javie dla niektórych danych wejściowych, więc Stringsą krótsze niż java.math.BigInteger. StringZmieniłem go jednak na tablicę, więc nie muszę robić podziału na kropki, co oszczędzało niektóre bajty, więc dziękuję.
Kevin Cruijssen
2

Excel VBA, 500 486 485 470 bajtów

Anonimowa funkcja natychmiastowego okna VBE

Anonimowa funkcja bezpośredniego okna VBE, która pobiera dane jako rok od [A1], miesiąc od [B1], dni od [C1], godziny od [D1], minuty od [E1], sekundy od [F1]i opcjonalna tablica o dodatkowej precyzji od [G1:Z1], oblicza znacznik czasu RFC2550 i wysyła dane do bezpośredniego okna VBE. Wykorzystuje zadeklarowaną funkcję pomocnika poniżej.

n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:Z1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p

Funkcja pomocnika

Zadeklarowana funkcja pomocnicza, która pobiera numer wejściowy i zwraca tę liczbę w bazie 26, tak że 1->Ai26->Z

Musi zostać umieszczony w module publicznym.

Function b(n)
While n
n=n-1
d=n Mod 26+1
n=Int(n/26)
d=d+26*(d<0):n=n-(d<0)
b=Chr(64+d)+b
Wend
End Function

Stosowanie

Muszą być stosowane w sposób jasny moduł lub moduł musi być usunięte przed wykonaniem co Vars j, oi pzakłada się, że w ich stanie niezainicjowane domyślnie na początku wykonanie kodu. Dla j, która jest Variant\Integerzmienną, ta wartość domyślna to, 0a dla oi p, które są Variant\Stringzmiennymi, ta wartość domyślna jest pustym ciągiem ( "").

Dane wejściowe, tablica ciągów znaków, są pobierane z 1:1arkusza ActiveSheet, a dane wyjściowe są przekazywane do bezpośredniego okna VBE.

Próbki we / wy

[A1:F1]=Split("4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11",".")
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711021028

Cells.Clear:j=0:o="":p="" '' clear the worksheet and vars
[A1:H1]=Array("-696443266","1","3","6","10","15","21","28")
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
*V3035567330103061015021028

Cells.Clear:j=0:o="":p="" '' clear the worksheet and vars
[A1]="45941"
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
A45941

Cells.Clear:j=0:o="":p="" '' clear the worksheet and vars
[A1:F1]=Split("4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11",".")
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711

Subrutynowa wersja

Zadeklarowany podprogram, który pobiera dane wejściowe jako rok od [A1], miesiąc od [B1], dni od [C1], godziny od [D1], minuty od [E1], sekundy od [F1]i opcjonalna tablica o dodatkowej precyzji od [G1:Z1], oblicza znacznik czasu RFC2550 i wysyła dane do bezpośredniego okna VBE.

Sub R(x)
a=x(0)
n=Left(a,1)="-"'<- that `"` is only there to make sure highlighting is correct
y=Mid(a,1-n)
l=Len(y)
o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y)
If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:o=IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))&Replace(o,"=","!")
For j=1To UBound(x)
o=o+IIf(x(j),Format(x(j),IIf(j>5,"000","00")),"")
Next
[A2]=o
End Sub
Function b(n)
While n
n=n-1
d=n Mod 26+1
n=Int(n/26)
d=d+26*(d<0):n=n-(d<0)
b=Chr(64+d)+b
Wend
End Function

Stosowanie

Wprowadzanie do zakresu [A1:ZZ1]można wykonać ręcznie, wpisując do komórki, od lewej do prawej, w zależności od potrzeb, lub przypisując z bezpośredniego okna VBE.

Należy zauważyć, że ze względu na automatyczne konwertowanie liczb Excela na notację naukową, wszelkie liczby o długości 10-bazowej równej lub większej niż 12 cyfr muszą zostać wstawione do komórki jawnie jako tekst poprzez ustawienie komórki jako komórki tekstowej lub przygotowując literał 'na początek wartości komórki

Próbki we / wy

r Split("4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11",".")
?[A2]  '' <- print output to VBE console
^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711 ''  <- Output

r Array("47883552573911529811831375872990","1","1","2","3","5","8","13")
?[A2]
^B478835525739115298118313758729900101020305008013

r Array("-696443266","1","3","6","10","15","21","28")
?[A2]
*V3035567330103061015021028

r Array("45941")
?[A2]
A45941

Nieoznakowany i wyjaśniony

''  Returns RFC2550 timestamp corresponding to passed vars
Public Function RFC2550(ByVal pYear As String, ParamArray Extra() As Variant) As String

    ''  Declare Vars
    Dim Negative As Boolean, _
        leny As Long, _
        i As Long, _
        c As Byte, _
        s As Variant, _
        out As String

    ''  Check if year is negative and store the absolute value of the year
    Let Negative = Left(pYear, 1) = "-"
    Let pYear = Mid(pYear, 1 - Negative)

    ''  Take the length of the year
    Let leny = Len(pYear)
    If leny < 5 Then
        ''  If the length is less than 5, pad the year left to 4 characters 
        ''  using zeros
        Let out = Format("0000", pYear)
    Else
        ''  If the length of the year is greater than 30, then set out to be 
        ''  as string comprised of length-30 instances of `^`
        Let out = IIf(leny < 31, "", String(Len(Base26(leny - 30)), 94)) 
        ''  append the Base26 representation of the length of the year,
        ''  minus 30, if the length is greater than 30
        Let out = out & Base26(leny - IIf(leny < 31, 4, 30)) 
        ''  append the year to out
        Let out = out & pYear
    End If


    If Negative Then
        ''  iterate across out
        For i = 1 To Len(out)
            ''  store the char code for the current char
            Let c = Asc(Mid(out, i, 1))
            ''  swap letter/number with its inverse (0->9,A->Z)
            Mid$(out, i, 1) = Chr(IIf(c < 60, 105, 155) - c)
        Next i

        ''  replace `=` (the inverse of `^`) with `!`
        Let out = Replace(out, "=", "!")
        ''  Prepend either `/`, `*`, or nothing depending on length and 
        ''  start of out
        Let out = IIf(leny < 5, "/", IIf(InStr(1, out, "!"), "", "*")) & out
    End If

    Let i = 1
    For Each s In Extra
        ''  append all of the extra precision data - padding to 2 chars for 
        ''  the first 5 elements in the array (month, day, hour, minute and 
        ''  second) and to 3 chars for all following elements (milli, micro, 
        ''  nano, pico, femto, atto, zepto, yocto - seconds) with the char 0
        Let out = out & IIf(s, Format(s, IIf(i > 5, "000", "00")), "")
        Let i = i + 1
    Next

    ''  return out
    Let RFC2550 = out 

End Function


''  returns non-standard base26 version of input number 
''  1->A, 2->B,... 26->Z
Function Base26(ByVal n As Long) As String

    ''  declare vars
    Dim out As String, _
        digit As Integer

    ''  init out, digit
    Let out = ""
    Let digit = 0

    ''  iterate through n 
    While n
        ''  Decrement, hold the value of the digit
        Let n = n - 1
        Let digit = n Mod 26 + 1

        ''  divide by 26
        Let n = Int(n / 26)

        ''  correct for negative numbers
        If digit < 0 Then Let n = n + 1: Let digit = digit - 26

        ''  prepend char corresponding to the digit to out
        Let out = Chr(64 + digit) & out
    Wend

    ''  return out
    Let Base26 = out
End Function
Taylor Scott
źródło
2

Galaretka , 165 126 bajtów

ḣ5ṫ€3
ØD,“^ /*!”,ØA
_µ‘l26Ċṗ@€ØAẎị@
Lµç30;€”^UZFµç4⁶;µ®L>30¤?µḟ®L>4¤?;®AṾ€¤µL=4”/x2£FiЀị€2£UF¤µ®S<0¤¡
4R¬+DU$UµḢ©Ç;Ñ;ṫ6ṫ€2$$F

Wypróbuj online!

Wiersz 4 wykonuje formatowanie roku przy pomocy wierszy 2 i 3. Pierwszy i ostatni wiersz dotyczą zerowania wypełniania elementów danych wejściowych do ich odpowiedniej długości, a następnie łączenia ich ze sformatowanym rokiem.

  • _µ‘l26Ċṗ@€ØAẎị@znajduje 26 podstawowy prefiks. Pobiera kartezjańską moc alfabetu ( ØA) dla każdej liczby od 1 do sufitu (log 26 (floor (log 10 (year)) - n + 1)) (gdzie n to 30 lub 4), a następnie pobiera indeksy do tej listy z podłogą (log 10 (rok)) - n ( ị@).
  • ç30;€”^UZF formaty lat> = 10 30 ( ®L>30¤?)
  • ç4⁶;formaty lat <10 30 . ( Edycja : Zapisano bajt za pomocą ⁶;zamiast ;@⁶)
  • 1RḊ daje pusty prefiks dla lat <10 5 ( ®L>4¤?). Pobiera listę cyfr, a następnie odfiltrowuje każdy element sam w sobie. Po prostu używam tego do plonu, []ponieważ tutaj nie działa. To tylko ocenia []. i []nie działają tutaj i nie mogłem znaleźć kolejnych 2 bajtów, które zwrócą pustą listę.
  • ;®AṾ€¤ dołącza rok do przedrostka, a następnie spłaszcza go.
  • L=4”/xprzedrostki a, /jeśli długość roku wynosi 4 w instrukcji do z ®S<0¤¡.
  • 2£FiЀ¹ị€2£UF¤przyjmuje uzupełnienia A .. Z, 0 .. 9a ^ /*!jeśli rok jest ujemny ( ®S<0¤¡). odnosi się do drugiego linku, ØD,“^ *!”,ØAktórym jest lista [['0' .. '9'], ['^',' ','/','*','!'], ['A' .. 'Z']]. Przy sformatowanym roku takim jak ^C125...ten link znajduje indeks każdego znaku w spłaszczonej wersji, a następnie używa tych indeksów do skonstruowania nowego ciągu ze spłaszczonej wersji miejsca odwrócenia każdej podlisty, tj . ['9' .. '0','!','*','/',' ','^','Z' .. 'A']Plonu !X874.... /odwzorowuje się do siebie, ponieważ jest prefiksowany, zanim wszystko zostanie uzupełnione.
  • L=4a®S<0x@”/;dodaje /na początku lat ujemnych w [-9999 .. -0001]. Domyślam się, że można to skrócić. Skończyło się na tym, że umieściłem to w poprzedniej instrukcji do ( ¡) i zapisałem 7 bajtów, ponieważ wtedy nie musiałem dwukrotnie testować ujemnych lat.

W ¡linii 4 jest wiele zastosowań i myślę, że można by je skompresować, używając ?zamiast tego, ale nie jestem pewien, jak sprawić, by działały. Zacząłem ?pracować i zaoszczędziłem kilka bajtów.

James Holderness zwrócił uwagę, że moje pierwsze zgłoszenie nie dotyczyło lat z poprawnymi 30 cyframi. Okazało się, że błąd występował w każdym roku, który wymagał Zprefiksu podstawowego 26. Okazuje się, że nie mogłem użyć, ponieważ po przekonwertowaniu 26 na bazę 26 daje to [1,0]zamiast 26(duh). Zamiast tego użyłem zamówionych par z zamiennikiem. Nie sądzę, że jest do tego atom, ale jeśli tak, mogę zaoszczędzić kilka bajtów. Naprawienie tego kosztowało mnie ~ 40 bajtów. Zdecydowanie mój najdłuższy jak dotąd program Jelly. Edycja : Znaleziono krótszy sposób wykonania produktu kartezjańskiego. Uświadomiłem sobie, że nie jestem pewien, czy ostatni działał dla prefiksów z więcej niż dwiema literami, ale nowy sposób działa.

Przepraszam, że wiele razy edytowałem ten post, po prostu odkrywam sposoby jego skracania.

dylnan
źródło