Всемирный день IPv6 2014

22

В ознаменование годовщины Всемирного дня IPv6 , Internet Society опубликовало кампанию « Выключить IPv4 6 июня 2014 года на один день» .


Адреса IPv6 могут быть представлены в их длинной форме в виде восьми 16-битных шестнадцатеричных значений, разделенных двоеточиями. В зависимости от адреса, они также могут быть сокращены, как описано в пункте 2 раздела 2.2. Текстовое представление адресов RFC 3513 :

Чтобы упростить запись адресов, содержащих нулевые биты, имеется специальный синтаксис для сжатия нулей. Использование «::» указывает одну или несколько групп из 16 битов нулей. «::» может появляться только один раз в адресе. «::» также можно использовать для сжатия начальных или конечных нулей в адресе.

  • Записи на этот вызов будет программы , которые принимают ровно один IPv6 - адрес , отформатированный в длинной или укороченной формате, и будет отображать один и тот же адрес в обоих длинных и коротких форматов, в таком порядке.

  • Входные данные могут поступать из аргументов командной строки, STDIN или любого другого входного источника, который соответствует вашему выбору языка.

  • Библиотеки или утилиты, специально предназначенные для анализа адресов IPv6, запрещены (например, inet_ {ntop, pton} () ).

  • Если входной адрес недействителен, вывод будет пустым (или выдается какое-то подходящее сообщение об ошибке, указывающее, что адрес недействителен )

  • В тех случаях, когда ::происходит сокращение, для данного адреса может выполняться только одна операция сокращения. Если для данного адреса существует более одной потенциальной операции сокращения, должна использоваться операция, которая дает общий кратчайший адрес. Если в этом отношении есть связь, будет использоваться первая операция. Это показано на примерах ниже.

  • Стандартные лазейки, которых следует избегать

Примеры:

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>

Это , поэтому самый короткий ответ в байтах 6 июня 2014 года будет принят победителем.

Цифровая травма
источник
Скажите, что вход 1:0:0:2:2::3. Будет ли сокращенный результат идентичным этому или 1::2:2:0:0:3? То же самое для неоптимально сокращенного ввода.
Мартин Эндер
@ m.buettner В этом случае я позволю вам выбрать либо.
Цифровая травма
Возможен ли 1::2:0:0:0:3ввод?
user12205
@ace В соответствии с принципом робастности покойного великого Джона Постеля , да.
Цифровая травма
2
Я думаю, что это единственный способ заставить меня учить ipv6. +1
Обострение

Ответы:

4

JavaScript (ES6) - 198 , 183 , 180 , 188 , 187 байт

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

И, немного длиннее, интерактивная версия с несколькими всплывающими окнами (203 байта):

/^(:[\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];
}

Объяснение:

Чтобы рассчитать длинную версию адреса IPv6:

8 - str.split(/:+/).length % 9- подсчитайте, сколько нулей нам нужно вставить. Их 8 - количество шестнадцатеричных значений. Здесь% 9 - защита, поэтому она никогда не будет отрицательным числом.

replace('::', ':0'.repeat(zeros || 1) + ':')- заменить "::" нулями, разделенными двоеточиями. Если нет нулей для добавления, он все равно добавляет один, поэтому адрес не будет действительным в конце

replace(/^:0|0:$/g, zeros ? '0:0' : '0')- это касается особого случая, когда адрес начинается или заканчивается на «::», так как splitфункция добавляет 1 к числу шестнадцатеричных значений (:: 1 -> ["», "1"])

Это оно! Теперь давайте посчитаем краткую форму:

replace(/(\b0(:0)*)(?!.*\1:0)/,':') - заменить самый длинный ряд нулей на двоеточие (не важно, сколько).

replace(/::+/,'::') - удалите лишние двоеточия, если таковые имеются

return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];- проверить, является ли длинная версия действительным IPv6, и вернуть обе версии или falseесли тест не пройден.

Тесты в 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
источник
Так намного лучше, чем у меня! Просто нужна некоторая коррекция для обработки ввода, как это :: 1 :,: 1 ::
edc65
Этот принял недействительным1:2:3:4::a:b:c:d
Kernigh
6

Javascript (E6) 246 305 284 292 319

Сильно пересмотренный Особый случай для :: специально обработанной фазы сжатия позволяет избежать цикла for (но на самом деле не очень короче) Я уверен, что окончательная фаза сжатия может быть сделана короче. Во всяком случае, не сейчас

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

Благодаря Nderscore

Как программа

Ввод и вывод с использованием js popup, в основном: p=prompt,p(F(p())) перезапись с помощью popup и без определения функции, количество символов должно быть меньше 260

Ungolfed и прокомментировал немного

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

Тест 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')

Тестовый вывод

"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
источник
Я бы предпочел программу, чем функцию. Я не знаю javascript достаточно хорошо, чтобы понять, возможно ли это.
Цифровая травма
@nderscore Упс - опечатка. Исправлено в новом комментарии.
Цифровая травма
Это может быть превращено в программу, получая информацию от prompt(). Вот некоторые оптимизации, которые довели его до 290: pastie.org/private/3ccpinzqrvvliu9nkccyg
nderscore
@nderscore: спасибо, 1-я замена не работает для input = '::', все равно отлично работает!
edc65
@ edc65 Я нашел исправление для этой замены :) pastie.org/private/kee0sdvjez0vfcmlvaxu8q
nderscore
4

Perl - 204 176 190 191 197

(202 символа + 2 за -pфлаг)

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

Пример:

$ 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

Объяснение:

# -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
МНИИП
источник
1
Msgstr "Умер в строке 1 ipv6.pl, <> строка 1" . Об этом спрашивали в комментариях к вопросу. Если есть сообщение, должно быть ясно, что это из-за неверного сообщения. Я попытался уточнить это в вопросе. В противном случае выглядит хорошо!
Цифровая травма
1
@DigitalTrauma Изменен dieна тихий выход.
Мниип
1
Жук? Эта программа принимает неверный адрес 1:2:3:4::a:b:c:d. Это раздражающий особый случай, потому что большинство адресов из восьми двоеточий являются недействительными, но ::2:3:4:a:b:c:dи 1:2:3:4:a:b:c::оба действительны
Kernigh
3

Сед, 276

У меня есть 275 байт в ipshorten.sed, плюс 1 байт для -r включения sed -rfиспользования расширенных регулярных выражений. Я использовал OpenBSD sed (1) .

Использование: 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/:$//

Я использую 22 регулярных выражения, так как sed не может сравнивать числа или составлять массивы. Для каждой строки ввода sed выполняет команды и печатает строку. Во время тестирования я поместил несколько строк предполагаемых IP-адресов в файл и передал этот файл в sed. Ссылка на расширенные регулярные выражения находится в re_format (7) .

  1. s/^/:/добавляет дополнительный двоеточие в начало строки. Я использую это дополнительное двоеточие для игры в гольф следующих двух команд.
  2. /^(:[0-9A-Fa-f]{0,4})*$/!dпроверяет, соответствует ли вся строка нулю или более группам двоеточий, за которыми следуют от нуля до четырех шестнадцатеричных цифр. !отменяет проверку, поэтому dудаляет строки со слишком большими шестнадцатеричными числами или с недопустимыми символами. Когда dудаляется строка, sed не запускает больше команд в этой строке.
  3. s/:0*([^:])/:\1/gудаляет первые 0 из каждого числа. Это изменило бы:0000:0000: на:0:0: . Я должен сделать это, потому что мой цикл сжатия работает только с однозначными нулями.
  4. s/://удаляет лишнее двоеточие. Удаляет только первый двоеточие.
  5. s/::/:=/меняет первый ::на :=. Это так, позже команды могут совпадать, =а не ::, и так= не считается двоеточием. Если нет ::, эта замена безопасно ничего не делает.
    • Теперь ::нужно сделать хотя бы один 0, но есть три разных случая для размещения этого 0.
  6. s/(.:=)(.)/\10:\2/это первый случай. Если ::был между двумя другими персонажами, то :=становится:=0: . Это единственный случай, который добавляет двоеточие.
  7. s/^:=/0&/это второй случай. Если:: был в начале строки, тогда поставьте 0 там.
  8. s/=$/&0/ это третий случай, для :: в конце строки.
  9. :E это метка для цикла расширения.
  10. /(.*:){7}/!{/=/!dначинается условный блок, если в строке меньше 7 двоеточий. /=/!dудаляет строки, у которых нет ::и не хватает двоеточий.
  11. s//=0:/добавляет одну двоеточие. Пустой //повторяет последнее регулярное выражение, так что это действительно так s/=/=0:/.
  12. bEветви, чтобы :Eпродолжить цикл.
  13. }закрывает блок Теперь в линии есть как минимум семь двоеточий.
  14. s/=//удаляет =.
  15. /^:|::|:$|(.*:){8}/dэто окончательная проверка после расширения. Он удаляет строки с начальным двоеточием, дополнительный, ::который не был расширен, завершающий двоеточие или восемь или более двоеточий.
  16. p печатает строку, которая является IP-адресом в полной форме.
  17. s/.*/:&:/ оборачивает адрес в дополнительные двоеточия.
    • Следующая задача состоит в том, чтобы найти самую длинную группу нулей, вроде :0:0:0:, и заключить ее в ::.
  18. s/:((0:)+)/:<\1>/gкушает каждую группу 0s, так :0:0:0:бы и стало :<0:0:0:>.
  19. :C является меткой для петли сжатия.
  20. s/0:>/>0:/gперемещает один 0 из каждого рта, так :<0:0:0:>стало бы :<0:0:>0:.
  21. /<0/{s/<>//gоткрывает условный блок, если какой-либо рот не пуст. s/<>//gудаляет все пустые рты, потому что эти группы слишком короткие.
  22. bC продолжает цикл сокращения.
  23. }закрывает блок Теперь любой рот пуст и отмечает самую длинную группу 0.
  24. s/<>(0:)+/:/контракты самая длинная группа, так :<>0:0:0:станет ::. В галстуке он выбирает пустой рот слева.
  25. s/<>//g удаляет любые другие пустые рты.
  26. /^::/!s/://удаляет первое лишнее двоеточие, если оно не является частью ::.
  27. /::$/!s/:$//делает это для последнего лишнего двоеточия. Затем sed печатает IP-адрес в краткой форме.
kernigh
источник
1

Python 3: 387 символов

Даже работает с неправильно укороченным вводом.

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

Двойная замена на « ':::'на '::'ощупь» выглядит очень плохо, но не уверен, как правильно справиться с самой длинной строкой 0, когда она упирается в один или оба конца.

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

Заменить финал passс , raiseчтобы увидеть , как это сбой защиты от некорректного ввода.

$ 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
Ник Т
источник
@DigitalTrauma исправлено. Я искал "0: 0: 0 ...", и он захватывал конечные 0
Ник Т
Вы действительно недостаточно слышите слово «примыкание»
Клаудиу
Жук? Эта программа принята, 1:2:3:4::a:b:c:dно отклонена ::2:3:4:a:b:c:dи 1:2:3:4:a:b:c::. Я считаю, что это было неправильно все три раза.
Kernigh