05AB1E has no UTF-8 conversion builtins, so I have to do everything manually..
Try it online or verify that it's a quine.
The shortest quine for 05AB1E is this one:
0"D34çý"D34çý (14 bytes) provided by @OliverNi. My answer uses a modified version of that quine by adding at the
0"D34çý..."D34çý.... A short explanation of this quine:
0 # Push a 0 to the stack (can be any digit)
"D34çý" # Push the string "D34çý" to the stack
D # Duplicate this string
34ç # Push 34 converted to an ASCII character to the stack: '"'
ý # Join everything on the stack (the 0 and both strings) by '"'
# (output the result implicitly)
Now for the challenge part of the code. As I mentioned at the top, 05AB1E has no UTF-8 conversion builtins, so I have to do these things manually. I've used this source as reference on how to do that: Manually converting unicode codepoints into UTF-8 and UTF-16. Here a short summary of that regarding the conversion of Unicode characters to Unicode†:
- Convert the unicode characters to their unicode values (i.e.
- Convert these unicode values to binary (i.e.
- Check in which of the following ranges the characters are:
0x00000000 - 0x0000007F (0-127):
0x00000080 - 0x000007FF (128-2047):
0x00000800 - 0x0000FFFF (2048-65535):
1110xxxx 10xxxxxx 10xxxxxx
0x00010000 - 0x001FFFFF (65536-2097151):
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
†: Unicode is capped at 21 bits, but UTF-8 is capped at 17 bits. So the range of 4 above would instead be:
0x00010000 - 0x0010FFFF (65536-1114111):
10000xxx 10xxxxxx 10xxxxxx 10xxxxxx
d will be in the first range, so 1 byte in UTF-8; character
Ж is in the second range, so 2 bytes in UTF-8; and character
丽 is in the third range, so 3 bytes in UTF-8.
x in the pattern behind it are filled with the binary of these characters, from right to left. So the
1100100) with pattern
10000010110) with pattern
110xxxxx 10xxxxxx becomes
11010000 10010110; and the
100111000111101) with pattern
1110xxxx 10xxxxxx 10xxxxxx becomes
1110x100 10111000 10111101, after which the remaining
x are replaced with
11100100 10111000 10111101.
So, that approach I also used in my code. Instead of checking the actual ranges, I just look at the length of the binary and compare it to the amount of
x in the patterns however, since that saves a few bytes.
Ç # Convert each character in the string to its unicode value
b # Convert each value to binary
ε # Map over these binary strings:
Dg # Duplicate the string, and get its length
•Xó• # Push compressed integer 8657
18в # Converted to Base-18 as list: [1,8,12,17]
@ # Check for each if the length is >= to this value
# (1 if truthy; 0 if falsey)
ƶ # Multiply each by their 1-based index
à # Pop and get its maximum
© # Store it in the register (without popping)
i # If it is exactly 1 (first range):
7j # Add leading spaces to the binary to make it of length 7
0ì # And prepend a "0"
ë # Else (any of the other ranges):
R # Reverse the binary
6ô # Split it into parts of size 6
Rí # Reverse it (and each individual part) back
ć # Pop, and push the remainder and the head separated to the stack
7®- # Calculate 7 minus the value from the register
j # Add leading spaces to the head binary to make it of that length
š # Add it at the start of the remainder-list again
Tì # Prepend "10" before each part
J # Join the list together
1®<× # Repeat "1" the value from the register - 1 amount of times
ì # Prepend that at the front
] # Close both the if-else statement and map
ð0: # Replace all spaces with "0"
J # And join all modified binary strings together
# (which is output implicitly - with trailing newline)
See this 05AB1E answer of mine (sections How to compress large integers? and How to compress integer lists?) to understand why