Światowy dzień IPv6 2014

22

Aby uczcić rocznicę Światowego dnia IPv6 , Towarzystwo Internetowe opublikowało kampanię Wyłącz IPv4 6 czerwca 2014 r. Na jeden dzień .


Adresy IPv6 mogą być reprezentowane w swojej długiej formie jako osiem 16-bitowych wartości szesnastkowych oddzielonych dwukropkami. W zależności od adresu można je również skrócić, jak opisano w punkcie 2 sekcji 2.2 Tekstowa reprezentacja adresów RFC 3513 :

Aby ułatwić pisanie adresów zawierających bity zerowe, dostępna jest specjalna składnia do kompresji zer. Użycie „::” oznacza jedną lub więcej grup 16 bitów zer. Znak „::” może pojawić się tylko raz w adresie. Znak „::” może także służyć do kompresji zer wiodących lub końcowych w adresie.

  • Zgłoszenia do tego wyzwania będą dotyczyły programów, które akceptują dokładnie jeden adres IPv6 sformatowany w formacie długim lub skróconym i wyświetlą ten sam adres zarówno w formacie długim, jak i krótkim, w tej kolejności.

  • Dane wejściowe mogą pochodzić z argumentów wiersza polecenia, STDIN lub dowolnego innego źródła wejściowego, które odpowiada Twojemu językowi.

  • Biblioteki lub narzędzia specjalnie do analizowania adresów IPv6 są zakazane (np. Inet_ {ntop, pton} () ).

  • Jeśli adres wejściowy jest nieprawidłowy, dane wyjściowe będą puste (lub zostanie wyświetlony odpowiedni komunikat o błędzie wskazujący, że adres jest nieprawidłowy )

  • W przypadkach, w których ::występuje skrócenie, dla danego adresu może wystąpić tylko jedna operacja skracania. Jeśli dla danego adresu istnieje więcej niż jedna potencjalna operacja skracania, należy użyć operacji, która daje ogólny najkrótszy adres. Jeśli w tym względzie istnieje remis, zostanie użyta pierwsza operacja. Ilustrują to poniższe przykłady.

  • Standardowe luki, których należy unikać

Przykłady:

Input                         Output

1080:0:0:0:8:800:200C:417A    1080:0:0:0:8:800:200C:417A
                              1080::8:800:200C:417A

FF01::101                     FF01:0:0:0:0:0:0:101
                              FF01::101

0:0:0:0:0:0:0:1               0:0:0:0:0:0:0:1
                              ::1

::                            0:0:0:0:0:0:0:0
                              ::

1:0:0:2:0:0:0:3               1:0:0:2:0:0:0:3
                              1:0:0:2::3

1:0:0:8:8:0:0:3               1:0:0:8:8:0:0:3
                              1::8:8:0:0:3

1:2:3:4:5:6:7:8               1:2:3:4:5:6:7:8
                              1:2:3:4:5:6:7:8

ABCD:1234                     <Invalid address format - no output>

ABCDE::1234                   <Invalid address format - no output>

1:2:3:4:5:6:7:8:9             <Invalid address format - no output>

:::1                          <Invalid address format - no output>

codegolf puzzle               <Invalid address format - no output>

To jest , więc najkrótsza odpowiedź w bajtach 6 czerwca 2014 roku zostanie zaakceptowana jako zwycięzca.

Cyfrowa trauma
źródło
Powiedz, że dane wejściowe to 1:0:0:2:2::3. Czy skrócona wydajność byłaby identyczna z tym 1::2:2:0:0:3? To samo dotyczy nieoptymalnie skróconego wejścia.
Martin Ender
@ m.buettner W tym przypadku pozwolę ci wybrać jedno z nich.
Cyfrowa trauma
Czy 1::2:0:0:0:3to możliwe wejście?
user12205
@ace Zgodnie z zasadą solidności późnego wielkiego Jona Postela , tak.
Cyfrowa trauma
2
Myślę, że to jedyny sposób, aby ktokolwiek kiedykolwiek zmusił mnie do nauki ipv6. +1
Obversity

Odpowiedzi:

4

JavaScript (ES6) - 198 , 183 , 180 , 188 , 187 bajtów

f=s=>/^(:[\da-f]{1,4}){8}$/i.test(':'+(s=s[r='replace'](d='::',':0'.repeat((n=8-s.split(/:+/).length%9)||1)+':')[r](/^:0|0:$/g,n?'0:0':0)))&&[s,s[r](/(\b0(:0)*)(?!.*\1:0)/,d)[r](/::+/,d)]

I, nieco dłuższa, interaktywna wersja z kilkoma wyskakującymi oknami (203 bajty):

/^(:[\da-f]{1,4}){8}$/i.test(':'+(s=(s=prompt())[r='replace'](d='::',':0'.repeat((n=8-s.split(/:+/).length%9)||1)+':')[r](/^:0|0:$/g,n?'0:0':0)))&&alert(s+'\n'+s[r](/(\b0(:0)*)(?!.*\1:0)/,d)[r](/::+/,d))

Nie golfowany:

function ipv6(str) {
    "use strict";
    var zeros = 8 - str.split(/:+/).length % 9

        ,longIP = str
            .replace('::', ':0'.repeat(zeros || 1) + ':')
            .replace(/^:0|0:$/g, zeros ? '0:0' : '0')

        ,shortIP = longIP
            .replace(/(\b0(:0)*)(?!.*\1:0)/,':')
            .replace(/::+/,'::');

    return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];
}

Wyjaśnienie:

Aby obliczyć długą wersję adresu IPv6:

8 - str.split(/:+/).length % 9- obliczyć, ile zer musimy wstawić. Są to 8 - liczba wartości szesnastkowych. Tutaj% 9 jest strażnikiem, więc nigdy nie będzie liczbą ujemną.

replace('::', ':0'.repeat(zeros || 1) + ':')- zamień „::” na zera oddzielone dwukropkiem. Jeśli nie ma żadnych zer do dodania, nadal dodaje jeden, więc adres nie będzie prawidłowy na końcu

replace(/^:0|0:$/g, zeros ? '0:0' : '0')- dotyczy to specjalnego przypadku, gdy adres zaczyna się lub kończy na „::”, ponieważ splitfunkcja dodaje 1 do liczby wartości szesnastkowych (:: 1 -> [„”, „1”])

To jest to! Teraz obliczmy krótki formularz:

replace(/(\b0(:0)*)(?!.*\1:0)/,':') - zamień najdłuższy rząd zer na dwukropek (s) (nieważne ile).

replace(/::+/,'::') - usunąć dodatkowe dwukropki, jeśli występują

return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];- sprawdź, czy długa wersja jest zgodna z IPv6, i zwróć obie wersje lub falsejeśli test się nie powiedzie.

Testy w przeglądarce Firefox:

>>> f('1080:0:0:0:8:800:200C:417A')
["1080:0:0:0:8:800:200C:417A", "1080::8:800:200C:417A"]
>>> f('FF01::101')
["FF01:0:0:0:0:0:0:101", "FF01::101"]
>>> f('0:0:0:0:0:0:0:1')
["0:0:0:0:0:0:0:1", "::1"]
>>> f('::')
["0:0:0:0:0:0:0:0", "::"]
>>> f('1:0:0:2:0:0:0:3')
["1:0:0:2:0:0:0:3", "1:0:0:2::3"]
>>> f('1:0:0:8:8:0:0:3')
["1:0:0:8:8:0:0:3", "1::8:8:0:0:3"]
>>> f('1:2:3:4:5:6:7:8')
["1:2:3:4:5:6:7:8", "1:2:3:4:5:6:7:8"]
>>> f('ABCD:1234')
false
>>> f('ABCDE::1234')
false
>>> f('1:2:3:4:5:6:7:8:9')
false
>>> f(':::1')
false
>>> f('1:2:3:4::a:b:c:d')
false
>>> f('codegolf puzzle')
false
rdzeń 1024
źródło
O wiele lepszy niż mój! Potrzebuję tylko poprawki do obsługi danych wejściowych takich jak ten: 1 :,: 1 ::
edc65
Ten zaakceptował nieważny1:2:3:4::a:b:c:d
kernigh
6

JavaScript (E6) 246 305 284 292 319

Znacznie zmieniony Specjalny przypadek dla :: specjalnie obsługiwanej fazy kompresji unika pętli for (ale nie jest to naprawdę bardzo krótszy) Jestem pewien, że końcową fazę kompresji można skrócić. W każdym razie nie teraz

F=i=>(c=':',d=c+c,z=':0'.repeat(9-i.split(c,9).length)+c,i=i==d?0+z+0:i[R='replace'](/^::/,0+z)[R](/::$/,z+0)[R](d,z>c?z:d),/^(:[\da-f]{1,4}){8}:$/i.test(k=c+i+c)&&[i,k[R]((k.match(/:(0:)+/g)||[]).sort().pop(),d)[R](/^:([^:])|([^:]):$/g,'$1$2')])

Dzięki nderscore

Jako program

Wejście i wyjście za pomocą wyskakującego js, ​​w zasadzie: p=prompt,p(F(p())) Przepisywanie z wyskakującym oknem i bez definicji funkcji, liczba znaków powinna być mniejsza niż 260

Nie golfił i skomentował trochę

F = i => (
  c = ':',
  d = c+c,
  z = ':0'.repeat(9-i.split(c,9).length) + c, 
  i = i == d ? 0+z+0 /* special case '::' */
    : i.replace(/^::/,0+z) /* special case '::...' */
       .replace(/::$/,z+0) /* special case '...::' */
       .replace(d, z > c ? z : d), /* here, if z==c, not valid: too much colons */
  /^(:[\da-f]{1,4}){8}:$/i.test(k = c+i+c) /* Check if valid */
  && [
   i, 
   k.replace((k.match(/:(0:)+/g)||[]).sort().pop(),d) /* find longest 0: sequence and replace it */
    .replace(/^:([^:])|([^:]):$/g,'$1$2') /* cut leading and trailing colons */
  ]
)

Testuj w konsoli

i=['1080:0:0:0:8:800:200C:417A'
, '::1:2:3:4:5:6:7', '1:2:3:4:5:6:7::'
, '1:2:3:4::5:6:7:8'
, ':1:2:3:4:5:6:7', '1:2:3:4:5:6:7:'
, 'FF01::101', '0:0:0:0:0:0:0:1'
, '::', '1::', '::1', ':::1', '1:::'
, '1:0:0:2:0:0:0:3', '1:0:0:0:2:0:0:3', '1::8:0:0:0:3'
, '1:2:3:4:5:6:7:8'
, 'ABCD:1234', 'ABCDE::1234', ':::', '::::::::::'
, '1:2:3:4:5:6:7:8:9', '::::1', 'codegolf puzzle'];
i.map(x=>x+' => '+F(x)).join('\n')

Wyjście testowe

"1080:0:0:0:8:800:200C:417A => 1080:0:0:0:8:800:200C:417A,1080::8:800:200C:417A
::1:2:3:4:5:6:7 => 0:1:2:3:4:5:6:7,::1:2:3:4:5:6:7
1:2:3:4:5:6:7:: => 1:2:3:4:5:6:7:0,1:2:3:4:5:6:7::
1:2:3:4::5:6:7:8 => false
:1:2:3:4:5:6:7 => false
1:2:3:4:5:6:7: => false
FF01::101 => FF01:0:0:0:0:0:0:101,FF01::101
0:0:0:0:0:0:0:1 => 0:0:0:0:0:0:0:1,::1
:: => 0:0:0:0:0:0:0:0,::
1:: => 1:0:0:0:0:0:0:0,1::
::1 => 0:0:0:0:0:0:0:1,::1
:::1 => false
1::: => false
1:0:0:2:0:0:0:3 => 1:0:0:2:0:0:0:3,1:0:0:2::3
1:0:0:0:2:0:0:3 => 1:0:0:0:2:0:0:3,1::2:0:0:3
1::8:0:0:0:3 => 1:0:0:8:0:0:0:3,1:0:0:8::3
1:2:3:4:5:6:7:8 => 1:2:3:4:5:6:7:8,1:2:3:4:5:6:7:8
ABCD:1234 => false
ABCDE::1234 => false
::: => false
:::::::::: => false
1:2:3:4:5:6:7:8:9 => false
::::1 => false
codegolf puzzle => false"   
edc65
źródło
Wolałbym program niż funkcję. Nie znam javascript wystarczająco dobrze, aby wiedzieć, czy jest to możliwe.
Cyfrowa trauma
@nderscore Oops - literówka. Poprawione w nowym komentarzu.
Cyfrowa trauma
Można go przekształcić w program, pobierając dane wejściowe z prompt(). Oto kilka optymalizacji, które sprowadzają go do 290: pastie.org/private/3ccpinzqrvvliu9nkccyg
nderscore
@nderscore: thx, 1st replace nie działa dla input = '::', i tak świetna robota!
edc65
@ edc65 Znalazłem naprawę tego zastąpienia :) pastie.org/private/kee0sdvjez0vfcmlvaxu8q
nderscore
4

Perl - 204 176 190 191 197

(202 znaków + 2 za -pflagę)

$_=uc;(9-split/:/)||/^:|:$/||last;s/^::/0::/;s/::$/::0/;s|::|':0'x(9-split/:/).':'|e;/::|^:|:$|\w{5}|[^A-F0-:].*\n/||(8-split/:/)and last;s/\b0*(?!\b)//g;print;s/\b((0:)*0)\b(?!.*\1:0\b)/::/;s/::::?/::/

Przykład:

$ perl -p ipv6.pl <<< 1:0:2:0::3
1:0:2:0:0:0:0:3
1:0:2::3
$ perl -p ipv6.pl <<< somethinginvalid
$ perl -p ipv6.pl <<< 1:2:0:4:0:6::8
1:2:0:4:0:6:0:8
1:2::4:0:6:0:8

Wyjaśnienie:

# -p reads a line from stdin and stores in $_
#
# Convert to uppercase
$_ = uc;

# Detect the annoying case @kernigh pointed out
(9 - split /:/) || /^:|:$/ || last;

# Fix :: hanging on the beginning or the end of the string
s/^::/0::/;
s/::$/::0/;

# Replace :: with the appropriate number of 0 groups
s|::|':0' x (9 - split /:/) . ':'|e;

# Silently exit if found an extra ::, a hanging :, a 5-char group, an invalid
# character, or there's not 8 groups
/::|^:|:$|\w{5}|[^A-F0-:].*\n/ || (8 - split /:/) and last;

# Remove leading zeros from groups
s/\b0*(?!\b)//g;

# Output the ungolfed form
print;

# Find the longest sequence of 0 groups (a sequence not followed by something
# and a longer sequence) and replace with ::
# This doesn't replace the colons around the sequence because those are optional
# thus we are left with 4 or 3 colons in a row
s/\b((0:)*0)\b(?!.*\1:0\b)/::/;

# Fix the colons after previous transformation
s/::::?/::/

# -p then prints the golfed form of the address
mniip
źródło
1
„Zmarł na ipv6.pl linia 1, <> linia 1” . O to pytano w komentarzach do pytania. Jeśli pojawia się komunikat, musi być jasne, że przyczyną jest niepoprawny komunikat. Próbowałem to wyjaśnić w pytaniu. W przeciwnym razie wygląda dobrze!
Cyfrowa trauma
1
@DigitalTrauma Zmieniono diena ciche wyjście.
mniip
1
Błąd? Ten program akceptuje nieprawidłowy adres 1:2:3:4::a:b:c:d. Jest to irytujące specjalny przypadek, ponieważ większość adresów osiem okrężnicy są nieważne, ale ::2:3:4:a:b:c:di 1:2:3:4:a:b:c::to zarówno ważny.
kernigh
3

sed, 276

Mam 275 bajtów w ipshorten.sed oraz 1 bajt dla -rprzełącznika w sed -rfcelu użycia rozszerzonych wyrażeń regularnych. Użyłem OpenBSD sed (1) .

Stosowanie: echo ::2:3:4:a:b:c:d | sed -rf ipshorten.sed

s/^/:/
/^(:[0-9A-Fa-f]{0,4})*$/!d
s/:0*([^:])/:\1/g
s/://
s/::/:=/
s/(.:=)(.)/\10:\2/
s/^:=/0&/
s/=$/&0/
:E
/(.*:){7}/!{/=/!d
s//=0:/
bE
}
s/=//
/^:|::|:$|(.*:){8}/d
p
s/.*/:&:/
s/:((0:)+)/:<\1>/g
:C
s/0:>/>0:/g
/<0/{s/<>//g
bC
}
s/<>(0:)+/:/
s/<>//g
/^::/!s/://
/::$/!s/:$//

Używam 22 wyrażeń regularnych, ponieważ sed nie może porównywać liczb ani tworzyć tablic. Dla każdego wiersza wejścia sed uruchamia polecenia i wypisuje wiersz. Podczas testowania umieściłem w pliku kilka wierszy rzekomych adresów IP i podałem ten plik do sed. Odniesienie do rozszerzonych wyrażeń regularnych znajduje się w re_format (7) .

  1. s/^/:/dodaje dodatkowy dwukropek na początku wiersza. Używam tego dodatkowego dwukropka do gry w golfa w następnych dwóch poleceniach.
  2. /^(:[0-9A-Fa-f]{0,4})*$/!dsprawdza, czy cała linia odpowiada zeru lub większej liczbie grup dwukropków, po których następuje zero do czterech cyfr szesnastkowych. !neguje sprawdzenie, więc dusuwa wiersze o zbyt dużych liczbach szesnastkowych lub niepoprawnych znakach. Kiedy dusuwa linię, sed nie uruchamia już więcej poleceń w tym wierszu.
  3. s/:0*([^:])/:\1/gusuwa początkowe 0 z każdej liczby. Zmieniłoby się :0000:0000:na :0:0:. Muszę to zrobić, ponieważ moja pętla skurczu działa tylko z jednocyfrowymi zerami.
  4. s/://usuwa dodatkowy dwukropek. Usuwa tylko pierwszy dwukropek.
  5. s/::/:=/zmienia pierwszy ::na :=. Jest to więc późniejsze polecenia można dopasować =zamiast ::, i tak =się nie liczy jako okrężnicy. Jeśli nie ::, to podstawienie bezpiecznie nic nie robi.
    • Teraz ::musi zrobić co najmniej jedno 0, ale istnieją trzy różne przypadki umieszczenia tego 0.
  6. s/(.:=)(.)/\10:\2/to pierwszy przypadek. Jeśli ::było między dwoma innymi postaciami, to :=staje się :=0:. Jest to jedyny przypadek, który dodaje dwukropek.
  7. s/^:=/0&/to drugi przypadek. Jeśli ::był na początku linii, wstaw tam 0.
  8. s/=$/&0/to trzeci przypadek, ::na końcu linii.
  9. :E jest etykietą dla pętli rozszerzeń.
  10. /(.*:){7}/!{/=/!drozpoczyna blok warunkowy, jeśli linia ma mniej niż 7 dwukropków. /=/!dusuwa linie, które nie miały ::i nie miały wystarczającej liczby dwukropków.
  11. s//=0:/dodaje jeden dwukropek. Pusty //powtarza ostatnie wyrażenie regularne, więc tak naprawdę jest s/=/=0:/.
  12. bErozgałęzienia, aby :Ekontynuować pętlę.
  13. }zamyka blok. Teraz linia ma co najmniej siedem dwukropków.
  14. s/=//usuwa =.
  15. /^:|::|:$|(.*:){8}/djest ostatnim sprawdzianem po rozwinięciu. Usuwa linie z wiodącym okrężnicą, dodatkowym, ::który nie został rozszerzony, okrężnicą końcową lub ośmioma lub więcej okrężnicami.
  16. p wypisuje linię, która jest długim adresem IP.
  17. s/.*/:&:/ zawija adres w dodatkowe dwukropki.
    • Następnym zadaniem jest znalezienie najdłuższej grupy zer, polubienie :0:0:0:i zawarcie jej ::.
  18. s/:((0:)+)/:<\1>/gzjada każdą grupę zer, więc :0:0:0:stałoby się :<0:0:0:>.
  19. :C jest etykietą dla pętli skurczowej.
  20. s/0:>/>0:/gprzesuwa jeden 0 z każdego ujścia, tak :<0:0:0:>by się stało :<0:0:>0:.
  21. /<0/{s/<>//gotwiera blok warunkowy, jeśli jakiekolwiek usta nie są puste. s/<>//gusuwa wszystkie puste usta, ponieważ te grupy są zbyt krótkie.
  22. bC kontynuuje pętlę skurczu.
  23. }zamyka blok. Teraz każde usta są puste i oznaczają najdłuższą grupę zer.
  24. s/<>(0:)+/:/skraca najdłuższą grupę, więc tak :<>0:0:0:się stanie ::. W remisie wybiera puste usta po lewej stronie.
  25. s/<>//g usuwa wszelkie inne puste usta.
  26. /^::/!s/://usuwa pierwszy dodatkowy dwukropek, chyba że jest on częścią ::.
  27. /::$/!s/:$//robi to dla ostatniego dodatkowego jelita grubego. Następnie sed drukuje adres IP w krótkiej formie.
kernigh
źródło
1

Python 3: 387 znaków

Działa nawet z nieprawidłowo skróconym wejściem.

$ echo '1::2:0:0:0:3' | python3 ipv6.py 
1:0:0:2:0:0:0:3
1:0:0:2::3

Podwójna zastąpić z ':::'ze '::'czuje się bardzo źle, ale nie wiem, jak do czynienia z czysto najdłuższy ciąg 0-tych, kiedy to przylega jednym lub obu końcach.

c=':'
p=print
try:
 B=[int(x,16)if x else''for x in input().split(c)];L=len(B)
 if any(B)-1:B=[''];L=1
 if L!=8:s=B.index('');B[s:s+1]=[0]*(9-L)
 for b in B:assert-1<b<2**16
 H=[format(x,'X')for x in B];o=c.join(H);p(o);n=''.join(str(h=='0')[0]for h in H)
 for i in range(8,0,-1):
  s=n.find('T'*i)
  if s>=0:H[s:s+i]=[c*2];p(c.join(H).replace(c*3,c*2).replace(c*3,c*2));q
 p(o)
except:0

Wymień finał passz raisezobaczyć, jak to się upaść chroniąc przed wejściem zniekształconych.

$ cat ipv6-test.sh 
echo '1080:0:0:0:8:800:200C:417A' | python3 ipv6.py
echo '1:2:3:4:5:6:7:8' | python3 ipv6.py
echo 'FF01::101' | python3 ipv6.py
echo '0:0:0:0:0:0:0:1' | python3 ipv6.py
echo '0:0:0:0:1:0:0:0' | python3 ipv6.py
echo '1:0:0:0:0:0:0:0' | python3 ipv6.py
echo '::' | python3 ipv6.py
echo '1:0:0:2:0:0:0:3' | python3 ipv6.py
echo '1::2:0:0:0:3' | python3 ipv6.py
echo '1:0:0:8:8:0:0:3' | python3 ipv6.py
echo 'ABCD:1234' | python3 ipv6.py
echo 'ABCDE::1234' | python3 ipv6.py
echo '1:2:3:4:5:6:7:8:9' | python3 ipv6.py
echo ':::1' | python3 ipv6.py
echo 'codegolf puzzle' | python3 ipv6.py
$ ./ipv6-test.sh 
1080:0:0:0:8:800:200C:417A
1080::8:800:200C:417A

1:2:3:4:5:6:7:8
1:2:3:4:5:6:7:8

FF01:0:0:0:0:0:0:101
FF01::101

0:0:0:0:0:0:0:1
::1

0:0:0:0:1:0:0:0
::1:0:0:0

1:0:0:0:0:0:0:0
1::


0:0:0:0:0:0:0:0
::

1:0:0:2:0:0:0:3
1:0:0:2::3

1:0:0:2:0:0:0:3
1:0:0:2::3

1:0:0:8:8:0:0:3
1::8:8:0:0:3
Nick T.
źródło
@DigitalTrauma poprawiony. Szukałem „0: 0: 0 ...” i przechwytywałem końcowe 0
Nick T
Naprawdę nie słyszysz dziś wystarczająco słowa „styka się”
Claudiu
Błąd? Ten program zaakceptował, 1:2:3:4::a:b:c:dale odrzucił zarówno ::2:3:4:a:b:c:di 1:2:3:4:a:b:c::. Uważam, że to było złe trzy razy.
kernigh