This is the reverse of this challenge.
Given an encoded list of codepoints and the characters used to encode it, you need to decompress it to its original string.
For example, given the encoded list [170, 76, 19, 195, 32]
and the encoder characters " abcdefghijklmnopqrstuvwxyz"
, the output should be "the fox"
.
How, though?
First, we need to go through the encoder characters and find out what bits they correspond to. We do this by getting the binary of each corresponding (1-indexed) index in the encoder string. For example, the encoder string 6923
:
6, index 1 => 1
9, index 2 => 10
2, index 3 => 11
3, index 4 => 100
Now we need to pad each with leading zeros until they are all of equal length:
6, index 1 => 001
9, index 2 => 010
2, index 3 => 011
3, index 4 => 100
Now that we have a lookup table, let's decode it. First, let's get the binary of each codepoint. Let's say we have codepoints [137, 147, 16]
(and still encoder string 6923
):
137 => 10001001
147 => 10010011
16 => 10000
The last one may not be 8 bits long. In this case, pad it with leading zeros until it is:
137 => 10001001
147 => 10010011
16 => 00010000
Now, smash all these bits into one string: 100010011001001100010000
. Now, we need to group it into sizes of how long each byte will be in the lookup table. Looking back at our lookup table with 6923
encoder string, we can see that each byte is 3 bits long. This means that we need to split the bits into chunks of 3:
100 010 011 001 001 100 010 000
Now, for each, check its character in the lookup table. If it is all zeros (and therefore not in the lookup table), ignore it.
100 => 3
010 => 9
011 => 2
001 => 6
001 => 6
100 => 3
010 => 9
000 is ignored
Now, joining this together, the string was 3926639
, and we're done!
Test cases
Codes: [170, 76, 19, 195, 32], encoder characters: " abcdefghijklmnopqrstuvwxyz" => "the fox"
Codes: [151, 20, 40, 86, 48], encoder characters: "123456789" => "971428563"
Codes: [170, 76, 25, 89, 68, 96, 71, 56, 97, 225, 60, 50, 21, 217, 209, 160, 97, 115, 76, 53, 73, 130, 209, 111, 65, 44, 16], encoder characters: " abcdefghijklmnopqrstuvwxyz" => "the quick brown fox jumps over the lazy dog"
Codes: [108], encoder characters: "abc" => "abc"
Codes: [255], encoder characters: "a" => "aaaaaaaa"
Codes: [85, 170], encoder characters: "ab" => "aaaabbbb"
Rules
- Second input can be a string, list, or even list of codepoints (same with output). It doesn't matter, I/O is very flexible for this challenge.
- First input can, again, be a list of the codepoints, or a string containing the represented codepoints (if your language uses an SBCS, you're free to use it (but you can still use UTF-8)). Again, I/O is flexible.
- Input will always be valid.
- Encoder characters will always contain less than 256 characters.
- Neither input will ever be empty.
- This is code-golf, so the shortest answer in bytes for each language wins.
- Standard I/O rules apply.
- Default loopholes are forbidden.
Reference implementation in JavaScript
function decode(points, encoderChars) {
const maxBitCount = Math.ceil(Math.log2(encoderChars.length + 1));
const charToBit = Object.fromEntries(encoderChars.map((c, i) => [c, (i + 1).toString(2).padStart(maxBitCount, "0")]));
const charBits =
points
.map((x) => x.toString(2).padStart(8, "0"))
.join("")
.match(RegExp(`.{1,${maxBitCount}}`, "g")) || [];
return charBits
.map((x) => Object.entries(charToBit).find((y) => y[1] === x)?.[0] || "")
.join("");
}
Attempt This Online! (feel free to steal the test case code for your own JS answer)