Hari IPv6 dunia 2014

22

Untuk menandai peringatan hari IPv6 Dunia , Internet Society telah menerbitkan kampanye untuk Matikan IPv4 pada 6 Juni 2014 untuk One Day .


Alamat IPv6 dapat direpresentasikan dalam bentuk panjang sebagai delapan nilai hex 16-bit yang dipisahkan oleh titik dua. Bergantung pada alamatnya, mereka juga dapat dipersingkat seperti yang dijelaskan dalam item 2 dari bagian 2.2 Representasi Teks dari Alamat RFC 3513 :

Untuk membuat alamat penulisan yang mengandung nol bit lebih mudah, sintaks khusus tersedia untuk mengompresi nol. Penggunaan "::" menunjukkan satu atau lebih grup dengan 16 bit nol. "::" hanya dapat muncul sekali dalam satu alamat. "::" juga dapat digunakan untuk mengompresi nol di depan atau di belakang alamat.

  • Entri untuk tantangan ini adalah program yang menerima tepat satu alamat IPv6 yang diformat dalam format panjang atau pendek, dan akan menampilkan alamat yang sama dalam format panjang dan pendek, dalam urutan itu.

  • Input mungkin berasal dari argumen baris perintah, STDIN, atau sumber input lain yang sesuai dengan pilihan bahasa Anda.

  • Perpustakaan atau utilitas khusus untuk mem -parsing alamat IPv6 dilarang (mis. Inet_ {ntop, pton} () ).

  • Jika alamat input tidak valid, output akan kosong (atau beberapa pesan kesalahan yang sesuai menunjukkan alamat tidak valid diberikan)

  • Dalam kasus di mana ::pemendekan terjadi, hanya satu operasi pemendekan dapat terjadi untuk alamat yang diberikan. Jika ada lebih dari satu operasi pemendekan potensial untuk alamat yang diberikan, operasi yang memberikan keseluruhan alamat terpendek harus digunakan. Jika ada ikatan dalam hal ini, operasi pertama akan digunakan. Ini diilustrasikan dalam contoh di bawah ini.

  • Celah standar harus dihindari

Contoh:

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>

Ini adalah , jadi jawaban tersingkat dalam byte pada 6 Juni 2014 akan diterima sebagai pemenang.

Trauma Digital
sumber
Katakan inputnya 1:0:0:2:2::3. Apakah output yang diperpendek akan identik dengan itu atau 1::2:2:0:0:3? Sama untuk input yang diperpendek secara tidak optimal.
Martin Ender
@ m.buettner Dalam hal ini, saya akan membiarkan Anda memilih.
Trauma Digital
Apakah 1::2:0:0:0:3mungkin input?
user12205
@ace Sesuai dengan prinsip Robustness Jon Postel yang hebat , ya.
Digital Trauma
2
Saya pikir ini adalah satu-satunya cara orang akan membuat saya belajar IPv6. +1
Kegemukan

Jawaban:

4

JavaScript (ES6) - 198 , 183 , 180 , 188 , 187 byte

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)]

Dan, versi yang lebih lama, interaktif dengan beberapa pop-up (203 byte):

/^(:[\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))

Tidak Disatukan:

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];
}

Penjelasan:

Untuk menghitung versi panjang dari alamat IPv6:

8 - str.split(/:+/).length % 9- hitung berapa nol yang perlu kita masukkan. Mereka adalah 8 - jumlah nilai hex. Di sini% 9 adalah penjaga sehingga tidak akan pernah menjadi angka negatif.

replace('::', ':0'.repeat(zeros || 1) + ':')- ganti "::" dengan nol yang dipisahkan dengan titik dua. Jika tidak ada nol untuk menambahkannya masih menambahkan satu sehingga alamat tidak akan valid pada akhirnya

replace(/^:0|0:$/g, zeros ? '0:0' : '0')- ini berkaitan dengan kasus khusus ketika alamat dimulai atau diakhiri dengan "::" karena splitfungsi menambahkan 1 ke jumlah nilai hex (:: 1 -> ["", "1"])

Itu dia! Sekarang mari kita hitung formulir singkat:

replace(/(\b0(:0)*)(?!.*\1:0)/,':') - ganti baris nol terlama dengan titik dua (tidak peduli berapa banyak).

replace(/::+/,'::') - hapus titik dua tambahan jika ada

return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];- uji apakah versi panjang IPv6 valid dan kembalikan kedua versi atau falsejika tes gagal.

Tes di 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
core1024
sumber
Jauh lebih baik dari milikku! Hanya perlu beberapa koreksi untuk menangani input seperti ini :: 1 :,: 1 ::
edc65
Yang ini menerima yang tidak valid1:2:3:4::a:b:c:d
kernigh
6

Javascript (E6) 246 305 284 292 319

Kasus khusus yang sangat direvisi untuk :: ditangani secara khusus, fase kompres menghindari loop for (tapi tidak terlalu pendek memang) Saya yakin bahwa fase kompres akhir dapat dibuat lebih pendek. Lagipula tidak sekarang

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')])

Terima kasih kepada nderscore

Sebagai sebuah program

Input dan output menggunakan js popup, pada dasarnya: p=prompt,p(F(p())) Menulis ulang dengan popup dan tanpa definisi fungsi, jumlah char harus di bawah 260

Tidak digabungkan dan berkomentar sedikit

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 */
  ]
)

Test In console

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')

Uji keluaran

"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
sumber
Saya lebih suka program daripada fungsi. Saya tidak tahu javascript cukup baik untuk mengetahui apakah ini mungkin.
Digital Trauma
@nderscore Ups - salah ketik. Diperbaiki dalam komentar baru.
Trauma Digital
Itu bisa dibuat menjadi program dengan mengambil masukan dari prompt(). Berikut adalah beberapa optimisasi yang membawanya ke 290: pastie.org/private/3ccpinzqrvvliu9nkccyg
nderscore
@nderscore: thx, ganti pertama tidak berfungsi untuk input = '::', lagipula kerja bagus!
edc65
@ edc65 Saya menemukan perbaikan untuk yang menggantikan :) pastie.org/private/kee0sdvjez0vfcmlvaxu8q
nderscore
4

Perl - 204 176 190 191 197

(202 karakter + 2 untuk -pbendera)

$_=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/::::?/::/

Contoh:

$ 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

Penjelasan:

# -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
sumber
1
"Meninggal di ipv6.pl baris 1, <> baris 1" . Ini ditanyakan dalam komentar pertanyaan. Jika ada pesan, harus jelas bahwa itu karena pesan yang tidak valid. Saya mencoba mengklarifikasi hal itu dalam pertanyaan. Kalau tidak, terlihat bagus!
Trauma Digital
1
@DigitalTrauma Diubah diemenjadi jalan keluar yang sunyi.
mniip
1
Bug? Program ini menerima alamat yang tidak valid 1:2:3:4::a:b:c:d. Ini merupakan kasus khusus menjengkelkan, karena sebagian besar alamat delapan usus tidak valid, tetapi ::2:3:4:a:b:c:ddan 1:2:3:4:a:b:c::keduanya berlaku.
kernigh
3

sed, 276

Saya memiliki 275 byte di ipshorten.sed, ditambah 1 byte untuk -rswitch sed -rfuntuk menggunakan ekspresi reguler yang diperluas. Saya menggunakan OpenBSD sed (1) .

Pemakaian: 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/:$//

Saya menggunakan 22 ekspresi reguler, karena sed tidak dapat membandingkan angka atau membuat array. Untuk setiap baris input, sed menjalankan perintah dan mencetak baris. Selama pengujian, saya menaruh beberapa baris alamat IP yang diduga dalam file, dan mengumpankan file ini ke sed. Referensi untuk ekspresi reguler yang diperluas ada di re_format (7) .

  1. s/^/:/menambahkan titik dua ekstra ke awal baris. Saya menggunakan titik dua ini untuk bermain golf dua perintah berikutnya.
  2. /^(:[0-9A-Fa-f]{0,4})*$/!dmemeriksa apakah seluruh baris cocok dengan nol atau lebih banyak kelompok titik dua diikuti oleh nol hingga empat digit heksadesimal. !meniadakan cek, jadi dhapus garis dengan angka heksadesimal yang terlalu besar atau dengan karakter yang tidak valid. Ketika dmenghapus suatu baris, sed tidak lagi menjalankan perintah pada baris ini.
  3. s/:0*([^:])/:\1/gmenghapus 0s terkemuka dari setiap nomor. Itu akan berubah :0000:0000:menjadi :0:0:. Saya harus melakukan ini karena loop kontraksi saya hanya berfungsi dengan 0-digit tunggal.
  4. s/://menghapus usus besar tambahan. Itu hanya menghapus usus besar pertama.
  5. s/::/:=/mengubah yang pertama ::menjadi :=. Ini adalah perintah kemudian yang bisa cocok =daripada ::, dan jadi =tidak dihitung sebagai titik dua. Jika tidak ada ::, penggantian ini dengan aman tidak melakukan apa-apa.
    • Sekarang ::harus membuat setidaknya satu 0, tetapi ada tiga kasus berbeda untuk menempatkan 0 ini.
  6. s/(.:=)(.)/\10:\2/adalah kasus pertama. Jika ::berada di antara dua karakter lain, maka :=menjadi :=0:. Ini adalah satu-satunya kasus yang menambahkan tanda titik dua.
  7. s/^:=/0&/adalah kasus kedua. Jika ::pada awal baris, maka letakkan 0 di sana.
  8. s/=$/&0/adalah kasus ketiga, untuk ::di akhir baris.
  9. :E adalah label untuk loop ekspansi.
  10. /(.*:){7}/!{/=/!dmemulai blok bersyarat jika garis memiliki kurang dari 7 titik dua. /=/!dmenghapus garis yang tidak memiliki ::dan tidak cukup titik dua.
  11. s//=0:/menambahkan satu titik dua. Kosong //mengulangi ekspresi reguler terakhir, jadi ini benar-benar s/=/=0:/.
  12. bEcabang untuk :Emelanjutkan loop.
  13. }menutup blok. Sekarang garis memiliki setidaknya tujuh titik dua.
  14. s/=//menghapus =.
  15. /^:|::|:$|(.*:){8}/dadalah pemeriksaan terakhir setelah ekspansi. Ini menghapus garis dengan usus besar yang memimpin, tambahan ::yang tidak diperluas, usus besar yang tertinggal, atau delapan atau lebih banyak titik dua.
  16. p mencetak baris, yang merupakan alamat IP dalam bentuk panjang.
  17. s/.*/:&:/ membungkus alamat dalam titik dua tambahan.
    • Tugas selanjutnya adalah menemukan grup 0s terpanjang, suka :0:0:0:, dan mengontraknya ::.
  18. s/:((0:)+)/:<\1>/gmakan setiap kelompok 0s, jadi :0:0:0:akan menjadi :<0:0:0:>.
  19. :C adalah label untuk loop kontraksi.
  20. s/0:>/>0:/gbergerak satu 0 dari setiap mulut, jadi :<0:0:0:>akan menjadi :<0:0:>0:.
  21. /<0/{s/<>//gmembuka blok bersyarat jika ada mulut yang tidak kosong. s/<>//gmenghapus semua mulut kosong, karena grup-grup itu terlalu pendek.
  22. bC melanjutkan loop kontraksi.
  23. }menutup blok. Sekarang setiap mulut kosong dan menandai kelompok 0s terpanjang.
  24. s/<>(0:)+/:/kontrak kelompok terpanjang, jadi :<>0:0:0:akan menjadi ::. Dalam dasi, ia mengambil mulut kosong di sebelah kiri.
  25. s/<>//g menghapus mulut kosong lainnya.
  26. /^::/!s/://menghapus usus besar tambahan pertama kecuali jika itu bagian dari ::.
  27. /::$/!s/:$//melakukannya untuk usus besar tambahan terakhir. Kemudian sed mencetak alamat IP dalam bentuk singkat.
kernigh
sumber
1

Python 3: 387 karakter

Bahkan bekerja dengan input yang diperpendek.

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

Penggantian ganda ':::'dengan '::'terasa sangat buruk tetapi tidak yakin cara menangani string terpanjang dengan 0 saat berbatasan dengan satu atau kedua ujungnya.

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

Ganti final passdengan raiseuntuk melihat bagaimana itu macet melindungi terhadap input yang salah format.

$ 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
sumber
@DigitalTrauma dikoreksi. Saya sedang mencari "0: 0: 0 ..." dan itu menangkap 0
Nick T
Anda benar-benar tidak cukup mendengar kata "berbatasan"
Claudiu
Bug? Program ini menerima 1:2:3:4::a:b:c:dtetapi menolak keduanya ::2:3:4:a:b:c:ddan 1:2:3:4:a:b:c::. Saya percaya itu salah tiga kali.
kernigh