World IPv6 day 2014
Javascript (E6) 246 305 284 292 319
Heavily revised
Special case for :: specifically handled, compress phase avoids the for loop (but not very shorter indeed)
I'm sure that the final compress phase can be made shorter. Not now anyway
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')])
Thanks to nderscore
As a program
Input and output using js popup, basically: p=prompt,p(F(p()))
Rewriting with popup and without the function definition, the char count should be under 260
Ungolfed and commented a bit
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 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')
Test output
"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"
Perl - 204 176 190 191 197
(202 chars + 2 for -p
flag)
$_=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/::::?/::/
Example:
$ 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
Explanation:
# -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
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)]
And, a bit longer, interactive version with some 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];
}
Explanation:
To calculate the long version of the IPv6 address:
8 - str.split(/:+/).length % 9
- calculate how many zeros we need to insert. They are 8 - the number of the hex values. Here % 9 is a guard so it will never be a negative number.
replace('::', ':0'.repeat(zeros || 1) + ':')
- replace the "::" with colon separated zeros. If there are no zeros to add it still adds one so the address won't be valid in the end
replace(/^:0|0:$/g, zeros ? '0:0' : '0')
- this deals with the special case when the address starts or ends with "::" as the split
function adds 1 to the number of hex values (::1 -> ["", "1"])
That's it! Now let's calculate the short form:
replace(/(\b0(:0)*)(?!.*\1:0)/,':')
- replace longest row of zeros with colon(s) (It doesn't matter how many).
replace(/::+/,'::')
- remove the extra colons if any
return /^(:[\da-f]{1,4}){8}$/i.test(':'+longIP) && [longIP, shortIP];
- test if the long version is valid IPv6 and return both versions or false
if the test fails.
Tests in 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