Dia Mundial do IPv6 2014

22

Para marcar o aniversário do dia mundial do IPv6 , a Internet Society publicou uma campanha para desativar o IPv4 em 6 de junho de 2014 por um dia .


Os endereços IPv6 podem ser representados em sua forma longa como oito valores hexadecimais de 16 bits separados por dois pontos. Dependendo do endereço, eles também podem ser reduzidos, conforme descrito no item 2 da seção 2.2 Representação de texto dos endereços da RFC 3513 :

Para facilitar a escrita de endereços contendo zero bits, está disponível uma sintaxe especial para compactar os zeros. O uso de "::" indica um ou mais grupos de 16 bits de zeros. O "::" pode aparecer apenas uma vez em um endereço. O "::" também pode ser usado para compactar zeros à esquerda ou à direita em um endereço.

  • As entradas para esse desafio serão os programas que aceitarem exatamente um endereço IPv6 formatado no formato longo ou abreviado e exibirão o mesmo endereço nos formatos longo e curto, nessa ordem.

  • A entrada pode vir de argumentos de linha de comando, STDIN ou qualquer outra fonte de entrada que seja adequada à sua escolha de idioma.

  • Bibliotecas ou utilitários especificamente para analisar endereços IPv6 são proibidos (por exemplo, inet_ {ntop, pton} () ).

  • Se o endereço de entrada for inválido, a saída estará vazia (ou será exibida alguma mensagem de erro adequada indicando que o endereço é inválido )

  • Nos casos em que ::ocorre encurtamento, apenas uma operação de encurtamento pode ocorrer para um determinado endereço. Se houver mais de uma potencial operação de encurtamento para um determinado endereço, a operação que fornecer o endereço mais curto geral deverá ser usada. Se houver um empate a esse respeito, a primeira operação será usada. Isso é ilustrado nos exemplos abaixo.

  • Lacunas padrão a serem evitadas

Exemplos:

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>

Como é um , a resposta mais curta em bytes em 6 de junho de 2014 será aceita como vencedor.

Trauma Digital
fonte
Digamos que a entrada seja 1:0:0:2:2::3. A saída reduzida seria idêntica a isso ou 1::2:2:0:0:3? O mesmo para entradas encurtadas de maneira não ideal.
Martin Ender
@ m.buettner Nesse caso, eu vou deixar você escolher também.
Digital Trauma
É 1::2:0:0:0:3uma entrada possível?
User12205 27/05
@ace De acordo com o grande princípio de robustez de Jon Postel , sim.
Digital Trauma
2
Eu acho que essa é a única maneira de alguém me fazer aprender o ipv6. +1
Obversidade

Respostas:

4

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

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

E, versão interativa um pouco mais longa, com alguns pop-ups (203 bytes):

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

Ungolfed:

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

Explicação:

Para calcular a versão longa do endereço IPv6:

8 - str.split(/:+/).length % 9- calcule quantos zeros precisamos inserir. Eles são 8 - o número dos valores hexadecimais. Aqui% 9 é um protetor, portanto nunca será um número negativo.

replace('::', ':0'.repeat(zeros || 1) + ':')- substitua o "::" por zeros separados por dois pontos. Se não houver zeros a serem adicionados, ele ainda será adicionado, para que o endereço não seja válido no final

replace(/^:0|0:$/g, zeros ? '0:0' : '0')- trata do caso especial quando o endereço começa ou termina com "::", pois a splitfunção adiciona 1 ao número de valores hexadecimais (:: 1 -> ["", "1"])

É isso aí! Agora vamos calcular o formato abreviado:

replace(/(\b0(:0)*)(?!.*\1:0)/,':') - substitua a linha mais longa de zeros por dois pontos (não importa quantos).

replace(/::+/,'::') - remova os dois pontos extras, se houver

return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];- teste se a versão longa é IPv6 válida e retorne ambas as versões ou falsese o teste falhar.

Testes no 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
fonte
Muito melhor que o meu! Só precisa de alguma correção para lidar com entradas como esta :: 1 :,: 1 ::
edc65
Este aceitou o inválido1:2:3:4::a:b:c:d
kernigh
6

Javascript (E6) 246305284292319

Revisado com muita atenção Caso especial para :: fase de compressão especificamente manipulada evita o loop for (mas não muito mais curto) . Tenho certeza de que a fase final de compressão pode ser reduzida. Agora não de qualquer maneira

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

Graças a nderscore

Como um programa

Entrada e saída usando js pop-up, basicamente: p=prompt,p(F(p())) Reescrevendo com pop-up e sem a definição da função, a contagem de caracteres deve estar abaixo de 260

Ungolfed e comentou um pouco

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

Console de teste

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

Saída de teste

"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
fonte
Eu prefiro um programa do que uma função. Não conheço javascript o suficiente para saber se isso é possível.
Digital Trauma
@nderscore Ops - erro de digitação. Corrigido em um novo comentário.
Digital Trauma
Isso pode ser transformado em um programa, com a entrada de prompt(). Aqui estão algumas otimizações que o reduzem a 290: pastie.org/private/3ccpinzqrvvliu9nkccyg
nderscore
@nderscore: thx, a primeira substituição não funciona para input = '::', ótimo trabalho de qualquer maneira!
Edc65 28/05
@ edc65 Encontrei uma correção para essa substituição :) pastie.org/private/kee0sdvjez0vfcmlvaxu8q
nderscore
4

Perl - 204 176 190 191 197

(202 caracteres + 2 para -psinalizador)

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

Exemplo:

$ 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

Explicação:

# -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
fonte
1
"Morreu na linha 1 do ipv6.pl, <> linha 1" . Isso foi perguntado nos comentários da pergunta. Se houver uma mensagem, deve ficar claro que é por causa de uma mensagem inválida. Eu tentei esclarecer isso na pergunta. Caso contrário, parece ser bom!
Digital Trauma
1
@DigitalTrauma Alterado diepara uma saída silenciosa.
Mniip 28/05
1
Um inseto? Este programa aceita o endereço inválido 1:2:3:4::a:b:c:d. Este é um caso especial irritante, porque a maioria dos endereços de dois pontos é inválida, mas ::2:3:4:a:b:c:de 1:2:3:4:a:b:c::são ambos válidos.
precisa saber é o seguinte
3

sed, 276

Eu tenho 275 bytes em ipshorten.sed, mais 1 byte para o -rswitch sed -rfusar expressões regulares estendidas. Eu usei o OpenBSD sed (1) .

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

Eu uso 22 expressões regulares, pois o sed não pode comparar números ou criar matrizes. Para cada linha de entrada, sed executa os comandos e imprime a linha. Durante o teste, coloquei várias linhas de supostos endereços IP em um arquivo e alimentei esse arquivo para sed. Uma referência a expressões regulares estendidas está em re_format (7) .

  1. s/^/:/adiciona dois pontos extras ao início da linha. Eu uso esse cólon extra para jogar golfe nos próximos dois comandos.
  2. /^(:[0-9A-Fa-f]{0,4})*$/!dverifica se a linha inteira corresponde a zero ou mais grupos de dois pontos seguidos por zero a quatro dígitos hexadecimais. !nega a verificação e dexclui linhas com números hexadecimais muito grandes ou com caracteres inválidos. Quando dexclui uma linha, sed não executa mais comandos nessa linha.
  3. s/:0*([^:])/:\1/gexclui 0s iniciais de cada número. Mudaria :0000:0000:para :0:0:. Eu devo fazer isso porque meu loop de contração funciona apenas com 0s de um dígito.
  4. s/://exclui os dois pontos extras. Exclui apenas o primeiro dois pontos.
  5. s/::/:=/muda o primeiro ::para :=. Isso ocorre para que os comandos posteriores possam corresponder =e não ::e, portanto =, não contam como dois pontos. Se não houver ::, essa substituição com segurança não fará nada.
    • Agora ::deve fazer pelo menos um 0, mas há três casos diferentes para colocar esse 0.
  6. s/(.:=)(.)/\10:\2/é o primeiro caso. Se ::estava entre dois outros caracteres, :=torna - se :=0:. Este é o único caso que adiciona dois pontos.
  7. s/^:=/0&/é o segundo caso. Se ::estava no início da linha, coloque 0 lá.
  8. s/=$/&0/é o terceiro caso, para ::no final da linha.
  9. :E é o rótulo para o loop de expansão.
  10. /(.*:){7}/!{/=/!dinicia um bloco condicional se a linha tiver menos de 7 pontos. /=/!dexclui linhas que não tinham ::e não eram dois pontos suficientes.
  11. s//=0:/adiciona um cólon. Vazio //repete a última expressão regular, então é isso mesmo s/=/=0:/.
  12. bEramifica para :Econtinuar o loop.
  13. }fecha o bloco. Agora a linha tem pelo menos sete dois pontos.
  14. s/=//exclui =.
  15. /^:|::|:$|(.*:){8}/dé uma verificação final após a expansão. Exclui linhas com dois pontos principais, um extra ::que não foi expandido, dois pontos à direita ou oito ou mais dois pontos.
  16. p imprime a linha, que é um endereço IP em formato longo.
  17. s/.*/:&:/ quebra o endereço em dois pontos extras.
    • A próxima tarefa é encontrar o grupo mais longo de 0s :0:0:0:, e contratá-lo ::.
  18. s/:((0:)+)/:<\1>/gcome cada grupo de 0s, assim :0:0:0:se tornaria :<0:0:0:>.
  19. :C é o rótulo do loop de contração.
  20. s/0:>/>0:/gmove um 0 de cada boca, assim :<0:0:0:>se tornaria :<0:0:>0:.
  21. /<0/{s/<>//gabre um bloqueio condicional se alguma boca não estiver vazia. s/<>//gexclui todas as bocas vazias, porque esses grupos são muito curtos.
  22. bC continua o ciclo de contração.
  23. }fecha o bloco. Agora qualquer boca está vazia e marca o grupo mais longo de 0s.
  24. s/<>(0:)+/:/contrai o grupo mais longo, por isso :<>0:0:0:se tornaria ::. Em um empate, ele pega a boca vazia à esquerda.
  25. s/<>//g exclui outras bocas vazias.
  26. /^::/!s/://exclui o primeiro dois pontos extras, a menos que faça parte ::.
  27. /::$/!s/:$//faz isso pelo último cólon extra. Então sed imprime o endereço IP em formato abreviado.
Kernigh
fonte
1

Python 3: 387 caracteres

Funciona até com entradas encurtadas incorretamente.

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

A substituição dupla de ':::'com '::'parece muito ruim, mas não tenho certeza de como lidar corretamente com a seqüência mais longa de 0s quando ela se limita a uma ou ambas as extremidades.

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

Substitua a final passpor raisepara ver como ela está travando, protegendo contra entradas malformadas.

$ 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
fonte
@DigitalTrauma corrigido. Eu estava procurando por "0: 0: 0 ..." e estava capturando 0s finais
Nick T
Você realmente não ouve a palavra "confina" o suficiente hoje em dia
Claudiu
Um inseto? Este programa aceitou, 1:2:3:4::a:b:c:dmas rejeitou ambos ::2:3:4:a:b:c:de 1:2:3:4:a:b:c::. Eu acredito que estava errado nas três vezes.
kernigh