Día mundial del IPv6 2014

22

Para conmemorar el aniversario del día mundial de IPv6 , Internet Society ha publicado una campaña para desactivar IPv4 el 6 de junio de 2014 durante un día .


Las direcciones IPv6 pueden representarse en su forma larga como ocho valores hexadecimales de 16 bits separados por dos puntos. Dependiendo de la dirección, también se pueden acortar como se describe en el elemento 2 de la sección 2.2 Representación de texto de direcciones de RFC 3513 :

Para facilitar la escritura de direcciones que contengan cero bits, hay disponible una sintaxis especial para comprimir los ceros. El uso de "::" indica uno o más grupos de 16 bits de ceros. El "::" solo puede aparecer una vez en una dirección. El "::" también se puede utilizar para comprimir ceros iniciales o finales en una dirección.

  • Las entradas a este reto serán los programas que aceptan exactamente una dirección IPv6 formateado en el formato largo o acortada, y mostrarán la misma dirección en ambos formatos largos y cortos, en ese orden.

  • La entrada puede provenir de argumentos de línea de comandos, STDIN o cualquier otra fuente de entrada que se adapte a su elección de idioma.

  • Las bibliotecas o utilidades específicamente para analizar direcciones IPv6 están prohibidas (por ejemplo, inet_ {ntop, pton} () ).

  • Si la dirección de entrada no es válida, la salida estará vacía (o aparece un mensaje de error adecuado que indica que la dirección no es válida )

  • En los casos en que se ::produce el acortamiento, solo puede ocurrir una operación de acortamiento para una dirección determinada. Si hay más de una posible operación de acortamiento para una dirección determinada, se debe utilizar la operación que proporciona la dirección más corta en general. Si hay un empate a este respecto, se utilizará la primera operación. Esto se ilustra en los ejemplos a continuación.

  • Lagunas estándar para evitar

Ejemplos:

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>

Este es , por lo que la respuesta más corta en bytes del 6 de junio de 2014 será aceptada como ganadora.

Trauma digital
fuente
Digamos que la entrada es 1:0:0:2:2::3. ¿La salida acortada sería idéntica a esa o 1::2:2:0:0:3? Lo mismo para la entrada no acortada de manera óptima.
Martin Ender
@ m.buettner En este caso, te dejaré elegir cualquiera.
Trauma digital
¿Es 1::2:0:0:0:3una entrada posible?
usuario12205
@ace De acuerdo con el principio de robustez del gran Jon Postel , sí.
Trauma digital
2
Creo que esta es la única forma en que alguien me hará aprender ipv6. +1
Obversidad

Respuestas:

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

Y, un poco más, versión interactiva con algunas ventanas emergentes (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))

Sin golf:

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

Explicación:

Para calcular la versión larga de la dirección IPv6:

8 - str.split(/:+/).length % 9- Calcule cuántos ceros necesitamos insertar. Son 8, el número de los valores hexadecimales. Aquí% 9 es un guardia, por lo que nunca será un número negativo.

replace('::', ':0'.repeat(zeros || 1) + ':')- reemplace el "::" con ceros separados por dos puntos. Si no hay ceros para agregar, todavía agrega uno, por lo que la dirección no será válida al final

replace(/^:0|0:$/g, zeros ? '0:0' : '0')- se trata del caso especial cuando la dirección comienza o termina con "::" ya que la splitfunción agrega 1 al número de valores hexadecimales (:: 1 -> ["", "1"])

¡Eso es! Ahora calculemos la forma corta:

replace(/(\b0(:0)*)(?!.*\1:0)/,':') - Reemplace la fila más larga de ceros con dos puntos (no importa cuántos).

replace(/::+/,'::') - eliminar los dos puntos adicionales si los hay

return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];- pruebe si la versión larga es IPv6 válida y devuelva ambas versiones o falsesi la prueba falla.

Pruebas en 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
fuente
¡Mucho mejor que el mío! Solo necesita alguna corrección para manejar entradas como esta :: 1 :,: 1 ::
edc65
Éste aceptó lo inválido1:2:3:4::a:b:c:d
kernigh
6

Javascript (E6) 246305284292319

Caso especial muy revisado para :: manejado específicamente, la fase de compresión evita el bucle for (pero no muy corto) Estoy seguro de que la fase de compresión final se puede acortar. No ahora de todos modos

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

Gracias a nderscore

Como un programa

Entrada y salida utilizando js popup, básicamente: p=prompt,p(F(p())) reescritura con popup y sin la definición de la función, el recuento de caracteres debe ser inferior a 260

Ungolfed y comentó un poco

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

Prueba en consola

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

Prueba de salida

"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
fuente
Prefiero un programa que una función. No conozco JavaScript lo suficientemente bien como para saber si esto es posible.
Trauma digital
@nderscore Oops - error tipográfico. Corregido en un nuevo comentario.
Trauma digital
Podría convertirse en un programa tomando la entrada de prompt(). Aquí hay algunas optimizaciones que lo reducen a 290: pastie.org/private/3ccpinzqrvvliu9nkccyg
nderscore
@nderscore: thx, el primer reemplazo no funciona para input = '::', ¡excelente trabajo de todos modos!
edc65
@ edc65 Encontré una solución para reemplazar :) pastie.org/private/kee0sdvjez0vfcmlvaxu8q
nderscore
4

Perl - 204 176 190 191 197

(202 caracteres + 2 para -pbandera)

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

Ejemplo:

$ 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

Explicación:

# -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
fuente
1
"Murió en ipv6.pl línea 1, <> línea 1" . Esto fue preguntado en los comentarios de la pregunta. Si hay un mensaje, debe quedar claro que se debe a un mensaje no válido. Traté de aclarar eso en la pregunta. De lo contrario se ve bien!
Trauma digital
1
@ DigitalTrauma cambiado diea una salida silenciosa.
mniip
1
¿Un insecto? Este programa acepta la dirección no válida 1:2:3:4::a:b:c:d. Este es un caso especial molesto, porque la mayoría de las direcciones de ocho de colon no son válidos, pero ::2:3:4:a:b:c:dy 1:2:3:4:a:b:c::son ambos válidos.
kernigh
3

sed, 276

Tengo 275 bytes en ipshorten.sed, más 1 byte para que el -rswitch sed -rfuse expresiones regulares extendidas. Usé 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/:$//

Utilizo 22 expresiones regulares, ya que sed no puede comparar números o hacer matrices. Para cada línea de entrada, sed ejecuta los comandos e imprime la línea. Durante las pruebas, puse varias líneas de supuestas direcciones IP en un archivo y alimente este archivo a sed. Una referencia a expresiones regulares extendidas está en re_format (7) .

  1. s/^/:/agrega dos puntos adicionales al comienzo de la línea. Utilizo este colon extra para jugar golf los siguientes dos comandos.
  2. /^(:[0-9A-Fa-f]{0,4})*$/!dcomprueba si la línea completa coincide con cero o más grupos de dos puntos seguidos de cero a cuatro dígitos hexadecimales. !niega el cheque, por lo que delimina líneas con números hexadecimales demasiado grandes o con caracteres no válidos. Cuando delimina una línea, sed no ejecuta más comandos en esta línea.
  3. s/:0*([^:])/:\1/gelimina los ceros a la izquierda de cada número. Cambiaría :0000:0000:a:0:0: . Debo hacer esto porque mi ciclo de contracción solo funciona con ceros de un solo dígito.
  4. s/://elimina el colon extra. Solo elimina el primer colon.
  5. s/::/:=/cambia el primero ::a :=. Esto es para que los comandos posteriores puedan coincidir en =lugar de ::, y =no cuentan como dos puntos. Si no hay:: , esta sustitución no hace nada con seguridad.
    • Ahora ::debe hacer al menos un 0, pero hay tres casos diferentes para colocar este 0.
  6. s/(.:=)(.)/\10:\2/Es el primer caso. Si ::estaba entre otros dos personajes, entonces se :=convierte en :=0:. Este es el único caso que agrega dos puntos.
  7. s/^:=/0&/Es el segundo caso. Si:: estaba al comienzo de la línea, entonces ponga 0 allí.
  8. s/=$/&0/ es el tercer caso, para :: al final de la línea.
  9. :E es la etiqueta para el bucle de expansión.
  10. /(.*:){7}/!{/=/!dcomienza un bloque condicional si la línea tiene menos de 7 puntos. /=/!delimina líneas que no tenían ::y no tenían suficientes dos puntos.
  11. s//=0:/agrega un colon. Vacío //repite la última expresión regular, así que esto es realmente s/=/=0:/.
  12. bEse ramifica para :Econtinuar el ciclo.
  13. }Cierra el bloque. Ahora la línea tiene al menos siete colones.
  14. s/=//borra =.
  15. /^:|::|:$|(.*:){8}/dEs un control final después de la expansión. Elimina líneas con un colon inicial, un extra ::que no se expandió, un colon posterior u ocho o más colonias.
  16. p imprime la línea, que es una dirección IP en forma larga.
  17. s/.*/:&:/ envuelve la dirección en dos puntos adicionales.
    • La siguiente tarea es encontrar el grupo más largo de 0, me gusta :0:0:0:y contraerlo ::.
  18. s/:((0:)+)/:<\1>/gcome cada grupo de ceros, por :0:0:0:lo que se convertiría :<0:0:0:>.
  19. :C es la etiqueta para el bucle de contracción.
  20. s/0:>/>0:/gmueve un 0 de cada boca, por :<0:0:0:>lo que se convertiría :<0:0:>0:.
  21. /<0/{s/<>//gabre un bloque condicional si alguna boca no está vacía. s/<>//gelimina todas las bocas vacías, porque esos grupos son demasiado cortos.
  22. bC continúa el ciclo de contracción.
  23. }Cierra el bloque. Ahora cualquier boca está vacía y marca el grupo más largo de ceros.
  24. s/<>(0:)+/:/contrata al grupo más largo, por :<>0:0:0:lo que se convertiría ::. En un empate, recoge la boca vacía a la izquierda.
  25. s/<>//g elimina cualquier otra boca vacía.
  26. /^::/!s/://elimina el primer colon extra a menos que sea parte de ::.
  27. /::$/!s/:$//lo hace para el último colon extra. Luego sed imprime la dirección IP en forma corta.
kernigh
fuente
1

Python 3: 387 caracteres

Incluso funciona con entradas incorrectamente acortadas.

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

El reemplazo doble de ':::'con se '::'siente realmente mal, pero no estoy seguro de cómo lidiar limpiamente con la cadena más larga de 0 cuando se topa con uno o ambos extremos.

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

Reemplace el final passcon raisepara ver cómo se bloquea la protección contra entradas mal formadas.

$ 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
fuente
@DigitalTrauma corregido. Estaba buscando "0: 0: 0 ..." y estaba capturando los ceros finales
Nick T
Realmente no escuchas la palabra "linda" hoy en día
Claudiu
¿Un insecto? Este programa aceptó 1:2:3:4::a:b:c:dpero rechazó ambos ::2:3:4:a:b:c:dy 1:2:3:4:a:b:c::. Creo que estuvo mal las tres veces.
kernigh