Recently I solved a challenge (problem 1 of the 3rd easy problem set of phase 2 of the '19 APL Competition) on abbreviating and expanding IP v6 addresses. For that matter, I had to write two functions, AbbreviateIPv6
and ExpandIPv6
. The first function ought to take a character vector of a v6 IP address and abbreviate it like this online tool. The second function ought to undo exactly what the first one did.
I need a community review because these two were among a series of problems rated as easy and while most of them were fairly easy to solve and could be decently solved in a couple of lines, I found really hard to write the AbbreviateIPv6
function so I think I overlooked something. What is more, I failed to find a solution that didn't use regular expressions, which bothered me even more.
First, a helper function:
:Namespace ReplaceFirst
_ReplaceFirst_ ← {
⍝ Operator that replaces the first occurrence of the left operand with the right operand.
⍝ e.g. ('ui' ReplaceFirst 'fafa') 'this ui is ui' gives 'this fafa is ui'
startAt ← ⊃⍸⍺⍺⍷⍵
stopAt ← startAt + (¯1+≢⍺⍺)×startAt>0
pruned ← ⍵/⍨ ~(startAt∘<∧≤∘stopAt)⍳≢⍵
replaceAt ← (>∘0⍴⊢) startAt
∊ ((⊂,⍵⍵)@replaceAt) pruned
}
:EndNamespace
that I used in the AbbreviateIPv6
function:
AbbreviateIPv6 ← {
⍝ Monadic function taking character vector as input and returning character vector.
⍝ Abbreviates an IP v6 address.
⍝ e.g. '2001:0DB8:0000:0042:0000:8A2E:0370:7334' becomes '2001:DB8:0:42:0:8A2E:370:7334'
ReplFirst←⎕fix 'file://path/to/ReplaceFirst.dyalog'
reduced ← ('0000' ':0{1,3}' ⎕R (,¨'0' ':'))⍵
runs ← ⌽ ⍴∘'0:'¨ 1+2×⍳7
shortened ← {(⍵ ReplFirst._ReplaceFirst_ '') reduced}¨ runs
((⊃∘⍋≢¨)⊃⊢) shortened
}
I know I could've defined the _ReplaceFirst_
as a function inside AbbreviateIPv6
specialized for the case I wanted, but I figured the function was getting so long I might as well write a general operator that I might reuse later.
Finally, just for comparison, I was able to write the ExpandIPv6
in a much more compact way:
ExpandIPv6 ← {
⍝ Monadic function expecting and returning character vector.
⍝ Expands an abbreviated IP v6 address.
⍝ e.g. '2041:0:140F::875B:131B' gives '2041:0000:140F:0000:0000:0000:875B:131B'.
colons ← +/':'=⍵
intermediate ← ('::' ⎕R(':0'⍴⍨ 3+2×7-colons))⍵
splits ← (':'∘≠⊆⊢) intermediate
LeftZeroPadder ← (⍴∘'0')∘(4∘-)∘≢,⊢
⊃ {∊⍺':'⍵}/ LeftZeroPadder¨ splits
}