Convert a date to xkcd notation In his xkcd about the ISO 8601 standard date format Randall snuck in a rather curious alternative notation:



The large numbers are all the digits that appear in the current date in their usual order, and the small numbers are 1-based indices of the occurrences of that digit. So the above example represents 2013-02-27.

Let's define an ASCII representation for such a date. The first line contains the indices 1 to 4. The second line contains the "large" digits. The third line contains the indices 5 to 8. If there are multiple indices in a single slot, they are listed next to each other from smallest to largest. If there are at most m indices in a single slot (i.e. on the same digit, and in the same row), then each column should have be m+1 characters wide and left-aligned:

2  3  1  4
0  1  2  3  7
5     67    8


See also the companion challenge for the opposite conversion.

The Challenge

Given an ISO 8601 date (YYYY-MM-DD), output the corresponding xkcd date notation.

You may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument and outputting the result via STDOUT (or closest alternative), function return value or function (out) parameter.

Any year from 0000 to 9999 is valid input.

Trailing spaces are allowed, leading spaces are not. You may optionally output a single trailing newline.

Standard code-golf rules apply.

Test Cases

2013-02-27
2  3  1  4
0  1  2  3  7
5     67    8

2015-12-24
2  3  1     4
0  1  2  4  5
   5  67 8

2222-11-11
     1234
1    2
5678

1878-02-08
   1     3  24
0  1  2  7  8
57    6     8

2061-02-22
2   4   1   3
0   1   2   6
5       678

3564-10-28
      1 4 2 3
0 1 2 3 4 5 6 8
6 5 7         8

1111-11-11
1234
1
5678

0123-12-30
1 2 3 4
0 1 2 3
8 5 6 7
JavaScript (ES6), 168 173

As an anonymous function. Using template strings, there is a newline near the end that is significant and included in the byte count.

d=&gt;d.replace(/\d/g,c=&gt;m=(l=((o[c]=o[c]||[b,c,b])[p/2&amp;~1]+=++p).length)&gt;m?l:m,t=[m=p=b='',b,b],o=[])&amp;o.map(x=&gt;x&amp;&amp;x.map((x,i)=&gt;t[i]+=(x+'     ').slice(0,m+1)))||t.join`
`


Less golfed

f=d=&gt;(
  // get the indices in o and the columns width in m
  m=0,
  p=0,
  o=[],
  d.replace(/\d/g,c=&gt;(
    o[c] = o[c]||['',c,''], // for each found digit :array with top indices, digit, bottom indices
    o[c][p/2 &amp; ~1] += ++p, // (p/2 and not 1) maps 0..3 to 0, 4..7 to 2
    l = o[c].length,
    m = l&gt;m ? l : m // max indices string length in m 
  )),
  // build the output in t
  t=['','',''],
  o.map(x=&gt; x &amp;&amp; x.map(
    (x,i) =&gt; t[i]+=(x+'     ').slice(0,m+1)) // left justify, max value of m is 4
  ),
  t.join`\n` // return output as a newline separated string
)   


Test snippet



f=d=&gt;
  d.replace(/\d/g,c=&gt;m=(l=((o[c]=o[c]||[b,c,b])[p/2&amp;~1]+=++p).length)&gt;m?l:m,t=[m=p=b='',b,b],o=[])&amp;
  o.map(x=&gt;x&amp;&amp;x.map((x,i)=&gt;t[i]+=(x+'     ').slice(0,m+1)))
  ||t.join`\n`


console.log=x=&gt;O.textContent+=x+'\n'

;['2013-02-27','2015-12-24','2222-11-11','1878-02-08','2061-02-22','3564-10-28','1111-11-11']
.forEach(t=&gt;console.log(t+'\n'+f(t)+'\n'))
&lt;pre id=O&gt;&lt;/pre&gt;