2014年世界IPv6日


22

为纪念世界IPv6日的周年纪念日,互联网协会在2014年6月6日发布了一项“关闭IPv4的活动”,为期一天


IPv6地址可以长格式表示为八个冒号分隔的16位十六进制值。根据地址的不同,它们也可以按照RFC 3513的2.2节的文本文本表示中 2项进行缩短:

为了使写入包含零位的地址更容易,可以使用特殊语法来压缩零。“ ::”的使用表示一组或多组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>

这是,因此将接受2014年6月6日以字节为单位的最短答案。


假设输入为1:0:0:2:2::3。缩短后的输出等于或等于1::2:2:0:0:3吗?对于非最佳缩短的输入相同。
马丁·恩德

@ m.buettner在这种情况下,我让您选择其中一个。
Digital Trauma 2014年

1::2:0:0:0:3一个可能的输入?
user12205 2014年


2
我认为这是任何人都会让我学习ipv6的唯一方法。+1
Obversity

Answers:


4

的JavaScript(ES6) - 198183180188,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))

取消高尔夫:

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

比我的好多了!只需进行一些校正即可处理这样的输入
:::::::

这个人接受了无效1:2:3:4::a:b:c:d
kernigh 2014年

6

Javascript(E6)246305284292319

大量修改 了::的特殊情况,专门处理了compress阶段,避免了for循环(但确实不是很短)。 我敢肯定,可以将最终的compress阶段缩短。反正现在

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弹出窗口进行输入和输出,基本上是: p=prompt,p(F(p())) 使用popup重写并且没有函数定义,字符数应在260以下

取消 评论并发表评论

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

在控制台中测试

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"   

我宁愿一个程序而不是一个功能。我不太了解javascript,无法知道是否可行。
Digital Trauma 2014年

@nderscore糟糕-错字。已在新评论中更正。
Digital Trauma 2014年

通过从中获取输入,可以将其制成程序prompt()。以下是一些将其降低到290的优化方法:pastie.org/private/3ccpinzqrvvliu9nkccyg
nderscore 2014年

@nderscore:thx,第一个替换不适用于输入='::',反正很棒!
edc65

@ edc65我找到了该替换的修复程序:) pastie.org/private/kee0sdvjez0vfcmlvaxu8q
nderscore 2014年

4

Perl-204 204176190191197197

(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
“死于ipv6.pl第1行,<>第1行”。在问题注释中对此进行了询问。如果有消息,则必须清楚是由于无效消息引起的。我试图在问题中澄清这一点。否则看起来不错!
数字创伤2014年

1
@DigitalTrauma更改die为静默出口。
mniip 2014年

1
有毛病吗 该程序接受无效的地址1:2:3:4::a:b:c:d。这是一个恼人的特殊情况,因为大多数八结肠地址是无效的,但::2:3:4:a:b:c:d1:2:3:4:a:b:c::都是有效的。
kernigh 2014年

3

sed,276

我在ipshorten.sed 275个字节,再加上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:。我必须这样做,因为我的收缩循环仅适用于一位数字0。
  4. s/://删除多余的冒号。它仅删除第一个冒号。
  5. s/::/:=/将第一个更改:::=。因此,以后的命令可以匹配,=而不是::,等等=不算作冒号。如果没有::,则此替换安全地不执行任何操作。
    • 现在::必须至少设置一个0,但是有3种不同的情况可以将其设置为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,例如like :0:0:0:,并将其压缩为::
  18. s/:((0:)+)/:<\1>/g吃每组0,所以:0:0:0:将变为:<0:0:0:>
  19. :C 是收缩循环的标签。
  20. s/0:>/>0:/g从每张嘴移1个,因此:<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地址。

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

将final替换为passraise以查看如何崩溃以防止格式错误的输入。

$ 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
Nick T

如今,您真的听不到“对接”这个词
克劳迪乌(Claudiu)2014年

有毛病吗 该程序接受1:2:3:4::a:b:c:d但拒绝了::2:3:4:a:b:c:d1:2:3:4:a:b:c::。我相信这三遍都是错的。
kernigh 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.