我有两个在0-31范围内的值。我希望能够用一个字符表示这两个值(例如,用64进制来解释我所说的1个字符是什么意思),但仍然能够知道这两个值是什么,以及哪个在前面。
找到一个具有1024个连续码点的不错的Unicode块,例如CJK Unified Ideographs,并将32*32的值映射到它们上。Python 3中:
def char_encode(a, b):
return chr(0x4E00 + a * 32 + b)
def char_decode(c):
return divmod(ord(c) - 0x4E00, 32)
print(char_encode(17, 3))
# => 倣
print(char_decode('倣'))
# => (17, 3)
当你提到Base64…这是不可能的。Base64编码中的每个字符只允许6位数据,而您需要10位来表示您的两个数字。
还要注意,虽然这只是一个字符,但它占用了两个或三个字节,这取决于您使用的编码。正如其他人所指出的,没有办法将10位数据塞进8位字节。
说明:a * 32 + b
只是将[0,32)范围内的两个数映射为[0,1024)范围内的单个数。例如,0 * 32 + 0 = 0
;31 * 32 + 31 = 1023
。chr
找到具有该码点的Unicode字符,但具有低码点的字符如0
是不可打印的,并且将是一个糟糕的选择,因此结果被转移到一个漂亮的大Unicode块的开始:0x4E00
是19968
的十六进制表示,并且是CJK统一表意文字块中的第一个字符的码点。使用样例输入"17 * 32 + 3 = 547
"、"19968 + 547 = 20515
"或"0x5023
"的十六进制形式,即字符"倣
"的码点。因此,chr(20515) = "倣"
.
char_decode
函数只是反向执行所有这些操作:如果a * p + b = x
,则a, b = divmod(x, p)
(参见divmod
)。如果是c = chr(x)
,则是x = ord(c)
(参见ord
)。我相信你知道如果w + r = y
,那么r = y - w
。在这个例子中,ord("倣") = 20515
;20515 - 0x4E00 = 547
;divmod(547, 32)
为(17, 3)
.
值[0,31]可以5位存储,从2**5 == 32
开始。因此,您可以在10位中明确地存储两个这样的值。相反,除非其他条件成立,否则您将无法从少于10位的数据中明确地检索到两个5位的值。
如果您使用的编码允许1024或更多不同的字符,您可以将您的对映射到字符。否则你就做不到。所以ASCII不能在这里工作,Latin1也不能。但几乎所有的"正常"Unicode编码是可以的。
请记住,对于像UTF-8这样的东西,实际字符将占用超过10位。如果这是一个问题,请考虑使用UTF-16左右。