Journée mondiale IPv6 2014

22

Pour marquer l'anniversaire de la journée mondiale IPv6 , l'Internet Society a publié une campagne pour désactiver IPv4 le 6 juin 2014 pour One Day .


Les adresses IPv6 peuvent être représentées sous leur forme longue par huit valeurs hexadécimales de 16 bits séparées par deux-points. Selon l'adresse, ils peuvent également être raccourcis comme décrit au point 2 de la section 2.2 Représentation textuelle des adresses de la RFC 3513 :

Afin de faciliter l'écriture d'adresses contenant zéro bit, une syntaxe spéciale est disponible pour compresser les zéros. L'utilisation de "::" indique un ou plusieurs groupes de 16 bits de zéros. Le "::" ne peut apparaître qu'une seule fois dans une adresse. Le "::" peut également être utilisé pour compresser des zéros de début ou de fin dans une adresse.

  • Les inscriptions à ce défi seront les programmes qui acceptent exactement une adresse IPv6 formatée soit dans le format long ou raccourci, et affichera la même adresse dans les deux formats longs et courts, dans cet ordre.

  • L'entrée peut provenir d'arguments de ligne de commande, STDIN ou de toute autre source d'entrée qui convient à votre choix de langue.

  • Les bibliothèques ou utilitaires spécifiquement pour l'analyse des adresses IPv6 sont interdits (par exemple inet_ {ntop, pton} () ).

  • Si l'adresse d'entrée n'est pas valide, la sortie sera vide (ou un message d'erreur approprié indiquant que l'adresse n'est pas valide est donné)

  • Dans les cas où le ::raccourcissement se produit, une seule opération de raccourcissement peut se produire pour une adresse donnée. S'il existe plusieurs opérations de raccourcissement possibles pour une adresse donnée, l'opération qui donne l'adresse la plus courte globale doit être utilisée. S'il y a égalité à cet égard, la première opération sera utilisée. Ceci est illustré dans les exemples ci-dessous.

  • Failles standard à éviter

Exemples:

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>

Ceci est , donc la réponse la plus courte en octets du 6 juin 2014 sera acceptée comme gagnante.

Traumatisme numérique
la source
Disons que l'entrée est 1:0:0:2:2::3. La sortie raccourcie serait-elle identique à celle ou 1::2:2:0:0:3? Idem pour une entrée raccourcie de manière non optimale.
Martin Ender
@ m.buettner Dans ce cas, je vous laisse choisir.
Digital Trauma
Est-ce 1::2:0:0:0:3une entrée possible?
user12205
@ace Conformément au principe de robustesse du regretté Jon Postel , oui.
Digital Trauma
2
Je pense que c'est la seule façon pour quiconque de me faire apprendre l'ipv6. +1
Obversité

Réponses:

4

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

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

Et, version un peu plus longue et interactive avec quelques pop-ups (203 octets):

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

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

Explication:

Pour calculer la version longue de l'adresse IPv6:

8 - str.split(/:+/).length % 9- calculer combien de zéros nous devons insérer. Ils sont 8 - le nombre de valeurs hexadécimales. Ici,% 9 est un gardien donc ce ne sera jamais un nombre négatif.

replace('::', ':0'.repeat(zeros || 1) + ':')- remplacez le "::" par des zéros séparés par deux points. S'il n'y a pas de zéros à ajouter, il en ajoute toujours un afin que l'adresse ne soit pas valide à la fin

replace(/^:0|0:$/g, zeros ? '0:0' : '0')- cela concerne le cas spécial où l'adresse commence ou se termine par "::" car la splitfonction ajoute 1 au nombre de valeurs hexadécimales (:: 1 -> ["", "1"])

C'est ça! Calculons maintenant la forme courte:

replace(/(\b0(:0)*)(?!.*\1:0)/,':') - remplacez la plus longue rangée de zéros par deux points (peu importe le nombre).

replace(/::+/,'::') - retirer les deux points supplémentaires le cas échéant

return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];- testez si la version longue est valide IPv6 et renvoyez les deux versions ou falsesi le test échoue.

Tests dans 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
la source
Tant mieux que le mien! A juste besoin d'une correction pour gérer les entrées comme ceci :: 1 :,: 1 ::
edc65
Celui-ci a accepté l'invalide1:2:3:4::a:b:c:d
kernigh
6

Javascript (E6) 246 305 284 292 319

Cas spécialement révisé pour :: spécifiquement traité, la phase de compression évite la boucle for (mais pas très courte en effet) Je suis sûr que la phase finale de compression peut être raccourcie. Pas maintenant de toute façon

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

Merci à nderscore

En tant que programme

Entrée et sortie en utilisant js popup, essentiellement: p=prompt,p(F(p())) réécriture avec popup et sans la définition de la fonction, le nombre de caractères doit être inférieur à 260

Ungolfed et commenté un peu

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

Sortie test

"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
la source
Je préfère un programme plutôt qu'une fonction. Je ne connais pas assez javascript pour savoir si c'est possible.
Digital Trauma
@nderscore Oups - faute de frappe. Corrigé dans un nouveau commentaire.
Digital Trauma
Il pourrait être transformé en programme en prenant des contributions de prompt(). Voici quelques optimisations qui le ramènent à 290: pastie.org/private/3ccpinzqrvvliu9nkccyg
nderscore
@nderscore: thx, le 1er remplacement ne fonctionne pas pour input = '::', excellent travail quand même!
edc65
@ edc65 J'ai trouvé un correctif pour ce remplacement :) pastie.org/private/kee0sdvjez0vfcmlvaxu8q
nderscore
4

Perl - 204 176 190 191 197

(202 caractères + 2 pour le -pdrapeau)

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

Exemple:

$ 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

Explication:

# -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
la source
1
Msgstr "Décédé à ipv6.pl ligne 1, <> ligne 1" . Cela a été demandé dans les commentaires de la question. S'il y a un message, il doit être clair que c'est à cause d'un message invalide. J'ai essayé de clarifier cela dans la question. Sinon, ça a l'air bien!
Digital Trauma
1
@DigitalTrauma Modifié dieen sortie silencieuse.
mniip
1
Un bug? Ce programme accepte l'adresse invalide 1:2:3:4::a:b:c:d. Ceci est un cas particulier gênant, car la plupart des adresses de huit côlon ne sont pas valides, mais ::2:3:4:a:b:c:det 1:2:3:4:a:b:c::sont valides.
kernigh
3

sed, 276

J'ai 275 octets dans ipshorten.sed, plus 1 octet pour que le -rcommutateur sed -rfutilise des expressions régulières étendues. J'ai utilisé OpenBSD sed (1) .

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

J'utilise 22 expressions régulières, car sed ne peut pas comparer les nombres ou faire des tableaux. Pour chaque ligne d'entrée, sed exécute les commandes et imprime la ligne. Pendant les tests, j'ai mis plusieurs lignes d'adresses IP présumées dans un fichier et ai alimenté ce fichier à sed. Une référence aux expressions régulières étendues se trouve dans re_format (7) .

  1. s/^/:/ajoute deux points supplémentaires au début de la ligne. J'utilise ces deux points supplémentaires pour jouer aux deux commandes suivantes.
  2. /^(:[0-9A-Fa-f]{0,4})*$/!dvérifie si la ligne entière correspond à zéro ou plusieurs groupes de deux-points suivis de zéro à quatre chiffres hexadécimaux. !annule la vérification, donc dsupprime les lignes avec des nombres hexadécimaux trop grands ou avec des caractères invalides. Lorsque dsupprime une ligne, sed n'exécute plus de commandes sur cette ligne.
  3. s/:0*([^:])/:\1/gsupprime les 0 en tête de chaque numéro. Cela changerait :0000:0000:en :0:0:. Je dois le faire car ma boucle de contraction ne fonctionne qu'avec des 0 à un chiffre.
  4. s/://supprime le côlon supplémentaire. Il supprime uniquement le premier côlon.
  5. s/::/:=/change le premier ::en :=. C'est ainsi que les commandes ultérieures peuvent correspondre =plutôt que ::, et =ne comptent donc pas comme deux points. S'il n'y a pas ::, cette substitution ne fait rien en toute sécurité.
    • Il ::faut maintenant faire au moins un 0, mais il y a trois cas différents pour placer ce 0.
  6. s/(.:=)(.)/\10:\2/est le premier cas. Si ::était entre deux autres personnages, alors :=devient :=0:. C'est le seul cas qui ajoute deux points.
  7. s/^:=/0&/est le deuxième cas. Si ::était au début de la ligne, mettez-y 0.
  8. s/=$/&0/est le troisième cas, ::en fin de ligne.
  9. :E est l'étiquette de la boucle d'expansion.
  10. /(.*:){7}/!{/=/!dcommence un bloc conditionnel si la ligne a moins de 7 points-virgules. /=/!dsupprime les lignes qui n'avaient pas ::et pas assez de deux-points.
  11. s//=0:/ajoute un colon. Vide //répète la dernière expression régulière, c'est vraiment le cas s/=/=0:/.
  12. bEbranches pour :Econtinuer la boucle.
  13. }ferme le bloc. Maintenant, la ligne a au moins sept deux-points.
  14. s/=//supprime =.
  15. /^:|::|:$|(.*:){8}/dest une dernière vérification après expansion. Il supprime les lignes avec un côlon de tête, un extra ::qui n'a pas été développé, un côlon arrière ou huit ou deux points.
  16. p imprime la ligne, qui est une adresse IP sous forme longue.
  17. s/.*/:&:/ encapsule l'adresse dans des deux points supplémentaires.
    • La tâche suivante consiste à trouver le plus long groupe de 0, comme :0:0:0:, et à le contracter ::.
  18. s/:((0:)+)/:<\1>/gmange chaque groupe de 0, :0:0:0:deviendrait ainsi :<0:0:0:>.
  19. :C est l'étiquette de la boucle de contraction.
  20. s/0:>/>0:/gse déplace d'un 0 de chaque bouche, :<0:0:0:>deviendrait ainsi :<0:0:>0:.
  21. /<0/{s/<>//gouvre un bloc conditionnel si une bouche n'est pas vide. s/<>//gsupprime toutes les bouches vides, car ces groupes sont trop courts.
  22. bC continue la boucle de contraction.
  23. }ferme le bloc. Maintenant, toute bouche est vide et marque le plus long groupe de 0.
  24. s/<>(0:)+/:/contrats le groupe le plus long, :<>0:0:0:deviendrait ainsi ::. En cravate, il prend la bouche vide à gauche.
  25. s/<>//g supprime toute autre bouche vide.
  26. /^::/!s/://supprime le premier côlon supplémentaire sauf s'il fait partie de ::.
  27. /::$/!s/:$//le fait pour le dernier colon supplémentaire. Sed imprime ensuite l'adresse IP sous forme abrégée.
kernigh
la source
1

Python 3: 387 caractères

Fonctionne même avec une entrée incorrectement raccourcie.

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

Le double remplacement de ':::'with '::'se sent vraiment mal, mais ne sait pas comment gérer proprement la plus longue chaîne de 0 lorsqu'elle touche une ou les deux extrémités.

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

Remplacez la finale passpar raisepour voir comment elle se bloque en protégeant contre une entrée mal formée.

$ 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
la source
@DigitalTrauma corrigé. Je cherchais "0: 0: 0 ..." et il capturait des 0 à la fin
Nick T
Vous n'entendez vraiment pas assez le mot "butée" de nos jours
Claudiu
Un bug? Ce programme a accepté 1:2:3:4::a:b:c:dmais rejeté à la fois ::2:3:4:a:b:c:det 1:2:3:4:a:b:c::. Je crois que c'était mal les trois fois.
kernigh