[Question]
  [
# Introduction
A code page maps integer values to a specific character. We can visualize a code page like this:
```
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 | q | w | e | r | t | z | u | i | o | p | a | s | d | f | g | j |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 1 | k | l | y | x | c | v | b | n | m | Q | W | E | R | T | Z | U |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 2 | I | O | P | A | S | D | F | G | H | J |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
```
The rows specify the first digit and the columns the second digit of the hex-number.
# The Challenge
Given a string of 16-255 unique characters, output the corresponding code page using the zero-based index of each character in the string as it's value.
The input `qwertzuiopasdfgjklyxcvbnmQWERTZUIOPASDFGHJ` for example would yield the table above.
* The output has to be in the exact same format as the table above. Only a trailing newline is optional.
* If the input length is not a multiple of 16, you need to start a new row for the remaining characters and leave the unused cells empty (=filled with 3 spaces).
* Each character is placed exactly in the middle of a cell, padded by one space to the left and right.
* The values in the first row and column are given by hex-numbers with the digits `0123456789ABCDEF`. Those are padded with one space to the left and right as well. You may choose to use lowercase hex-digits but you need to stick to one.
* The only characters present in the output are hyphens `-`, pluses `+`, pipes `|`, spaces , the digits for hexadecimal numbers and the characters from the input.
* Any builtins that are related to ASCII-art tables or trivialize the problem in any way are forbidden.
* You may assume that the input consists only of characters of a specific encoding. Please specify if that is the case.
* If your language can **only** handle ASCII input, you may assume ASCII-only input and repeated characters.
# Rules
* Function or full program allowed.
* [Default rules](http://meta.codegolf.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods) for input/output.
* [Standard loopholes](http://meta.codegolf.stackexchange.com/questions/1061/loopholes-that-are-forbidden-by-default) apply.
* This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so lowest byte-count wins. Tiebreaker is earlier submission.
**Happy Coding!**
  
[Answer]
## Pyth, 60 bytes
```
K+*"+---"hJ16\+Vm++"| "j" | "d" |"+]+]d.HMJ.e+.Hk.[bdJczJNK
```
The leading newline is significant.
[Try it here.](https://pyth.herokuapp.com/?code=%0A%0AK%2B%2a%22%2B---%22hJ16%5C%2BVm%2B%2B%22%7C+%22j%22+%7C+%22d%22+%7C%22%2B%5D%2B%5Dd.HMJ.e%2B.Hk.%5BbdJczJNK&input=qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJ&debug=0)
[Answer]
# Python 3.5, 326 355 bytes:
(*+29 bytes since if the length of the last row is **not** a multiple of 16, unused cells should be left empty (although, in my opinion, it looks much better if those empty cells are just not even shown)*)
```
def f(r):o=' 0123456789ABCDEF';r=[r[0+i:16+i]for i in range(0,len(r),16)];print('+---'*17+'+\n|',end='');[print(' {} |'.format(h),end='')for h in o];print(''.join([str(e+' | ')if e.isdigit()or e.isalpha()else str(e)for e in''.join([str('\n'+'+---'*17+'+\n| '+x[0]+x[1])for x in zip(o[1::1],r)])]),end='');print('  |'+'   |'*(15-len(r[-1]))+'\n'+'+---'*17+'+')
```
Works like a charm!
**Sample Inputs and Outputs:**
```
Input: 'hopper'
Output:
    
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    |   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    | 0 | h | o | p | p | e | r |   |   |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Input: 'honkhonkhonkhonkhonk'
Output:
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    |   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    | 0 | h | o | n | k | h | o | n | k | h | o | n | k | h | o | n | k | 
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    | 1 | h | o | n | k |   |   |   |   |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    
Input: 'hi'
Output: 
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    |   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    | 0 | h | i |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
```
I hope this is okay.
Also, here is another version I created for this challenge, which, although is an invalid candidate since it does **not** print out extra empty cells for the last row if its length is not a multiple 16, in my opinion outputs a much better looking page than the one required by OP, mainly because it does not even show empty cells if the last row is not a multiple of 16, but instead just shows filled cells, and that's it:
```
def f2(r):o=' 0123456789ABCDEF';r=[r[0+i:16+i]for i in range(0,len(r),16)];print('+---'*17+'+\n|',end='');[print(' {} |'.format(h),end='')for h in o];print(''.join([str(e+' | ')if e.isdigit()or e.isalpha()else str(e)for e in''.join([str('\n'+'+---'*17+'+\n| '+x[0]+x[1])for x in zip(o[1::1],r)])]));print('+---'*(len(r[-1])+1)+'+')
```
Here is a sample input and output for the inapplicable code above:
```
Input: 'ggreuuobgugoubgoubguorgoruguor'
Output:
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    |   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    | 0 | g | g | r | e | u | u | o | b | g | u | g | o | u | b | g | o | 
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    | 1 | u | b | g | u | o | r | g | o | r | u | g | u | o | r | 
    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
    (As you can see, there are no empty cells shown in the entire table. This looks much better to me.)
```
[Answer]
# Excel VBA, ~~157~~ 146 Bytes (Cheating?)
Anonymous VBE Immediate Window function that destructively takes input from range `[A1]` and outputs to the `ActiveSheet` object.
### Golfed
```
[B1:Q1]="=Dec2Hex(Column(B1)-2)":L=[Len(A1)]:For i=0To l:Cells(i\16+2,i Mod 16+2)=Mid([A1],i+1,1):Next:For i=1To l\16+1:Cells(i+1,1)=i:Next:[A1]="
```
### Formatted
```
[B1:Q1]="=Dec2Hex(Column(B1)-2)"
L=[Len(A1)]
For i=0To l:Cells(Int(i/16)+2,i Mod 16+2)=Mid([A1],i+1,1):Next
For i=1To Int(l/16)+1:Cells(i+1,1)=i:Next
[A1]=""
```
### Input / Output
Given:
```
[A1]="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJ"
```
the generated output is
[![Table thingy](https://i.stack.imgur.com/NM6YD.png)](https://i.stack.imgur.com/NM6YD.png)
[Answer]
# Excel (Version 1911), 247
```
A1 =DEC2HEX(COLUMN(A1:P1)-1)
A2 'Input String
A3 =2+LEN(A2)/16
A4 =CONCAT(" ",C2#)
A5 =TEXTJOIN("
"&REPT("+---",17)&"+
",0,,"| "&MID(A4,B2#+1,1)&" | "&MID(TEXTJOIN(" | ",0,A1#,MID(A2&REPT(" ",16),HEX2DEC(C2#&A1#)+1,1)),B2#*64+1,61)&" |",) ' Output
B2 =SEQUENCE(A3)-1
C2 =DEC2HEX(SEQUENCE(A3-1)-1)
```
Sample Test
[![Sample test](https://i.stack.imgur.com/Mqg6S.png)](https://i.stack.imgur.com/Mqg6S.png)
# Excel (Joke answer), 88 Bytes
Not a valid solution, but fun
```
B2 'Input
C4 =DEC2HEX(SEQUENCE(,16,0))
B5 =DEC2HEX(SEQUENCE(1+LEN(B2)/16)-1)
C5 =MID(B2,HEX2DEC(B5#&C4#)+1,1)
```
Output
[![enter image description here](https://i.stack.imgur.com/oipow.png)](https://i.stack.imgur.com/oipow.png)
[Answer]
# [05AB1E](http://github.com/Adriandmen/05AB1E), ~~65~~ 63 bytes
Code:
```
"+---"17×'+J©,žhAu6£¹J16÷)v„| ?N>iðëN<16B}y«ð17×ðñvy„ |ðJ?}¶?®,
```
[Try it online!](http://05ab1e.tryitonline.net/#code=IistLS0iMTfDlycrSsKpLMW-aEF1NsKjwrlKMTbDtyl24oCefCA_Tj5pw7DDq048MTZCfXnCq8OwMTfDl8Oww7F2eeKAniB8w7BKP33Ctj_Criw&input=ISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fiDCocKiwqPCpMKlwqbCp8KowqnCqsKrwqzCrsKvwrDCscKywrPCtMK1wrbCt8K4wrnCusK7wrzCvcK-wr_DgMOBw4LDg8OEw4XDhsOHw4jDicOKw4vDjMONw47Dj8OQw5HDksOTw5TDlcOWw5fDmMOZw5rDm8Ocw53DnsOfw6DDocOiw6PDpMOlw6bDp8Oow6nDqsOrw6zDrcOuw6_DsMOxw7LDs8O0w7XDtsO3w7jDucO6w7vDvMO9w77Dvw). Uses **CP-1252** encoding.
[Answer]
## JavaScript (ES6), 148 bytes
```
s=>(s=' 0123456789ABCDEF'+s+' '.repeat(15)).match(/(?!^).{16}/g).map((t,i)=>d+`+
| `+[s[i],...t].join` | `,d=`+---`.repeat(17)).join` |
`+` |
${d}+`
```
The `' 0123456789ABCDEF'` exists to populate the first column, but conveniently also covers the first row. The input string is then padded with spaces to allow it to be split into substrings of length 16, with the `(?!^)` preventing the leading space from being matched. The rest is just joining up the pieces.
[Answer]
# [PowerShell](https://github.com/TryItOnline/TioSetup/wiki/Powershell), ~~127~~ ~~126~~ 121 bytes
```
($d='+---'*17+'+')
($n="0123456789ABCDEF$args"+' '*16)|sls '.{16}'-a|% m*|% v*|%{"$($n[$i++-1]+$_|% t*y|%{"| $_"}) |"
$d}
```
[Try it online!](https://tio.run/##K8gvTy0qzkjNyfn/X0MlxVZdW1dXV13L0FxbXVtdk0tDJc9WycDQyNjE1MzcwtLRydnF1U0lsSi9WElbXQGozkyzpjinWEFdr9rQrFZdN7FGVSFXC0iUAYlqJRWg/miVTG1tXcNYbZV4oHiJViVIokZBJV6pVlOhRolLJaX2////6oVAd5RUlWbmFyQWp6SlZ2Rl51RWJJcl5eUGhrsGhUSFevoHOAa7uLl7eKkDAA "PowerShell – Try It Online")
[Answer]
# [Perl 5](https://www.perl.org/) `-pF`, ~~134~~ ~~109~~ 106 bytes
```
@F=(@a=($",0..9,A..F),@F);shift@F;printf+($_="+---"x@a.'+
')."|%2s "x@a."|
",$a[$i++],splice@F,0,16while@F
```
[Try it online!](https://tio.run/##HcjbCoIwAADQd78ihpGyCzMoCBEm1LpAdCcoIqy0VkuXsyt9eyt6OxwV57JmDOOBw6LAsQGihDRQSAh3EeOurw8iKRj3VS7SIoGOvQ4AxBiDB4tIBVoVl4B3uapL/wBvCyA7WtoCwhXSSoptzDiiyKvfD0L@bMzlHufF6yoyFeldsj@e5POxvW3S82jeGk8Xs@5gGE6avN3pfTJViCzVBvdrhHrUYMW/ "Perl 5 – Try It Online")
[Answer]
# [Perl 5](https://www.perl.org/) `-pl`, ~~127~~ 120 bytes
```
@.=($",0..9,A..F);$\='+---'x@..'+
';$_=join'',@.,s;.{1,16};$.[$.++].sprintf'%-16s',$&;gre;s;.;| $& ;g;s;.{1,68};$\$&|
;g
```
[Try it online!](https://tio.run/##JcvLCoJAFADQfV8RMTmFM5dcJMVFMOi96U1QRvRQsUwnx8pev94UtD9HuElYVcoGq0QKrAJQZw2AdhmJY1Gdc04zG4DqOYpkbR3iIKKU2cAkwtNghvlGAksCur4CKZIgSj1a5IYpKSMa@omLP4ivPNHy6OM/mbVfcoj2yqGv1PnmJunjEsRiI/eefziG92x33Uan0bw1ni5mvcGwMWm2O93@JxZpEEdScRF@AQ "Perl 5 – Try It Online")
Previous version:
```
@.=($",0..9,A..F);$~='+'.'---+'x@.;$_=join'',@.,s;.{1,16};$.[$.++].sprintf'%-16s',$&;gre;s;.;| $& ;g;s;.{1,68};$~
$&|
;g;$_.=$~
```
[Try it online!](https://tio.run/##JcvLasJAFIDhfZ5CymlGyczBLAzKIRDBptaNdwRFxLYxJE2TMRMvrTGP3jHQ7c//ySBPOlp76DbhibcRe7yP6LcIKpdZDJkQwmJXDwl2bpxFKWPcQ64Ibza3nTsBbgAta4tK5lFaHNizsB3FOJgU5gHVI5UNMBsU0j9yujWqDDBLo26wQxcqrY@XIC9@T1Em9@rzEMZfyc/14/yefk9XL7PFevk2nvTnA/91OPrLZBFlqdJCJg8 "Perl 5 – Try It Online")
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E), ~~47~~ 45 bytes
Thanks to [Kevin Cruijssen](https://codegolf.stackexchange.com/users/52210/kevin-cruijssen) for -2 bytes!
```
16ôí16jí15ÝhJš¬ðìsøv"+---"69∍=yS3j€ÀõšĆ'|ý,},
```
[Try it online!](https://tio.run/##AXMAjP9vc2FiaWX//zE2w7TDrTE2asOtMTXDnWhKxaHCrMOww6xzw7h2IistLS0iNjniiI09eVMzauKCrMOAw7XFocSGJ3zDvSx9LP//cXdlcnR6dWlvcGFzZGZnamtseXhjdmJubVFXRVJUWlVJT1BBU0RGR0hK "05AB1E – Try It Online")
**Commented**:
```
16ô                     # split the input into groups of (up to) 16
   í16jí                # right-pad the groups to 16 with reverse, left-pad, reverse
        15Ý             # push [0, 1, ..., 15]
           hJ           # convert each number to hexadecimal and join into string
                        #  => "0123456789ABCDEF"
               š        # prepend this string to the list
                ¬       # get the string back from the list
                 ðìs    # prepend a space
                    ø   # zip the list and the string
v              }        # iterate over the list
 "+---"                 # push the string "+---"
       69∍              # extend it to length 69
          =             # print it without removing the string from the stack
 y                      # push the current entry
  S                     # split into a list of characters
   3j                   # left-pad each to 3 chars with spaces
     €À                 # rotate each string left
       õšĆ              # prepend and append the empty string
          '|ý           # join by "|"
             ,          # print the string
,                       # after the loop: print "+---"69∍, which is still on the stack
```
[Try the first part with step-by-step output](https://tio.run/##fY@9TsMwFEZ3nuKqS0FKomRoJJAQYmFgY2JADE5yGzsktvFPW/ouDOytxMDAjMVzBSe00CqFb7Aly@fc@wlNMoZtm6TuDQ5lpGXNDBiKwLi0xp9GQKmElRrEFI6tBCNOIEnPYJTG1cX5kafcOkkrtx7IFCupCSUpeuHG4n1JCnNmKCicodIYQI3T/l@wfdq190km7nlfLq2mcBcHkAQQRZG/J/cDzIde71K54H6AASQ5BW6bDFW3EcUFKTBnDamB8AIqwfh3d20U4@UhcZfPl999FEr06DgOTy/Dq3Gn7WrXTJu/cPhYaffqVnsCAlqSHLf8/wv00e7d80smfwb2JYZ02z7OffulZUISXUzL6qF@WuSzjDc3t18)  
[Try one loop-iteration with step-by-step output](https://tio.run/##bZG/TsMwEMb3PsXJSwaIVAgEioQQf1@AETG46bV2FGzLvgoiMSAGxMJDsLMyMgVepC8S7BLRNM1JJ1nWfb/v/Fk7PpZY1wNgW3EcM@gWM3MngASCIyvVDKIwFx0BS4f5yfGgGUtHi9e3jhIfCNUEJAFpKFDNSPi5ldJBb60cs7m1qAh827LleN2vc6bwXlJ5Nw6FdAR6CpnglmeE1rVXTvI@QIFTig2fAPJMhKWTpdzBvfSrO8MzdOsPXzx/VE@bIKuJE/5hmtgCuxta9fnz/v3Sfb1FE2Ljoc3yGLLAO0NlA@tyfEWP1VebkmupYFz6@/@vqusbBmwb2HBnN9nbTw8OR6dn5xeXV@z2Fw)
]